-
Notifications
You must be signed in to change notification settings - Fork 0
ColorThemeEditor Guide
The Color Theme Editor is Fracturing Fog's modeless live-preview palette authoring tool. This guide covers every control, the persistence model, and 20 worked examples.
Companion pages: User Index · ColorGen DSL Guide

The picture on screen is made of two layers stacked on top of each other:
- The fractal — a black silhouette of points inside the set, surrounded by points outside it.
- The palette — a paint-by-numbers rule that says "this number of escape steps ⇒ this colour".
The Theme Editor lets you edit that paint-by-numbers rule live, with the fractal repainting itself as you drag sliders. Nothing you do here changes the math; it only changes how the math is visualised.
| Thing | Plain meaning |
|---|---|
| Colour Stops | A list of (position, colour) pairs. The picture fades between them in order. |
| Kind | Which colouring trick is applied: Gradient, Cycling, Phong3D (faux 3-D), Pbr3D (physically based). |
| Live Preview | When the checkbox is ticked, edits appear in the main window within ~150 ms. |
- Open Floating Menu → Edit Theme… (or press
T). - Pick Kind = Gradient.
- Empty the existing stop list and create four new stops:
- position
0.00—#1A0040(very dark purple) - position
0.40—#C42E1C(deep orange-red) - position
0.75—#FFB347(warm orange) - position
1.00—#FFF4B5(pale yellow)
- position
- Tick Live Preview. The fractal repaints with the sunset.
- Tweak each stop's position by dragging it left/right. Watch the colour zones grow / shrink.
- Type a name (
Sunset over Mandelbrot) and click Save to Library. - The new theme appears in the main Theme dropdown — you can pick it any time.

- Click From Image… at the bottom of the editor.
- Pick any JPG / PNG (an album cover, a landscape photo, a fabric swatch).
- The Image Palette helper opens, samples the photo with k-means in CIELAB colour space, and gives you back five evenly-spaced stops.
- Click Use as Stops. The Color Stops list is replaced.
- Tick Live Preview — the fractal now wears the photo's palette.
Tip
The Image Palette helper sorts stops by hue, then by lightness. If you want a cooler palette from a warm photo, swap stops 1↔5 and 2↔4 by dragging their position handles.
- Open the editor.
- Switch Kind = Pbr3D (physically-based 3-D lighting).
-
Steepness =
1.5. Ambient =0.10. Glow exp =2.0, Glow scale =0.4. - Material bands: a single entry with
metallic = 0.95,roughness = 0.15. - Drag the Key Light direction so it falls roughly top-left. Set its Diffuse RGB to a
warm white
#FFEBD0. - Tick Live Preview. The fractal grows a metallic sheen with crisp specular highlights.
- Opening the Editor
- Layout
- Identity Section
- Kind Selector
- Color Stops
- Randomize — Random Theme Generator
- Cycle Speed
- 3D Lighting (Phong + PBR)
- Phong3D Extras
- Pbr3D Extras
- In-Set Color
- Post-FX Defaults
- Live Preview + Actions
- Image Palette Helper
- JSON Schema
- Worked Examples
- Tips + Troubleshooting
Three entry points:
- Toolbar Edit Theme button.
- Floating Menu → Color Themes → Edit Theme… button.
- Hotkey
T.
The editor seeds from the currently-selected theme. Cancel-without-Save restores the previously active theme on close — your live preview edits don't pollute the library.
┌──────────────────────────────────────────────────────────────────┐
│ Target : Region ▾ Base theme ▾ │
│ Identity: Name __________ Kind ▾ Category ▾ │
│ Description ___________ Max zoom _____ │
├──────────────────┬───────────────────────────────────────────────┤
│ Color Stops │ 3D Lighting │
│ Add 🎲Random │ Steepness ___ Ambient ___ │
│ From/Import/Exp │ Key Dir XYZ Diffuse RGB Spec RGB Shine │
│ ☐Experim ☑In-set│ Fill Dir XYZ Diffuse RGB Spec RGB Shine │
│ ☐Post-FX │ ☐ Rim light │
│ Seed ___ ☐Use │ │
│ ☑Interp │ │
│ ☐Inspect ◎ │ │
│ [pos] [swatch] │ │
│ [pos] [swatch] │ │
│ Cycle │ Phong3D extras │
│ Speed ___ │ Key/Fill/Rim spec + diff scales │
│ │ │
│ In-Set │ Pbr3D extras │
│ ☐ Override RGBA │ Lighting mode ▾ Glow exp / scl │
│ │ Material bands [start end metal rough] … │
│ Post-FX defaults │ │
│ Brightness ___ │ │
│ Contrast ___ │ │
│ Adaptive ___ │ │
│ │ │
│ Actions │ │
│ ☑ Live preview │ │
│ [Apply] [Blank] │ │
│ [Revert] │ │
│ [Save] [Export] │ │
│ [Save C#] │ │
│ [From Image…] │ │
└──────────────────┴───────────────────────────────────────────────┘
Sections collapse when irrelevant — Phong3D / PBR3D extras hide for Gradient + Cycling kinds.
| Field | Purpose |
|---|---|
| Name | Library key. Must be unique within colorthemes.json. |
| Kind | Gradient / Cycling / Phong3D / Pbr3D |
| Category | Free-form grouping label (used by the right-click sort menu) |
| Description | Optional free-text annotation |
| Max zoom | Optional metadata — UI does not enforce; future-proofing for adaptive theme switching |
Save behavior: if the typed Name already exists in the library, the editor prompts to confirm overwrite. Cancel returns to the editor with the existing entry untouched.
| Kind | When to use |
|---|---|
| Gradient | Single-pass linear ramp across the iter range. Best for escape-time + distance-estimation maps where the iteration count is roughly monotonic. |
| Cycling | Repeats the gradient N times along the iter axis. Best for revealing fine band structure in shallow + medium zooms. |
| Phong3D | Cycling gradient + Blinn-Phong directional lighting computed from a synthesized surface normal (the Z component is built from the iter derivative). Gives a relief-mapped look. |
| Pbr3D | Cycling gradient + Cook-Torrance physically-based shading + per-band metallic/roughness. Gives a real-material look (chrome, brushed steel, ceramic, glass). |
Changing Kind shows / hides the relevant lighting sections.
| Control | Behavior |
|---|---|
| Position [0, 1] | Normalised stop along the gradient. 0 = low iter, 1 = high iter. |
| Swatch | Click for the color picker. RGB / hex entry below the swatch also works. |
| Add | Insert a new stop above the selected one. |
| Delete | Remove the selected stop. Editor enforces ≥ 2 stops. |
| Reorder | Drag the position handle to reposition. |
Stops interpolate linearly between adjacent positions. Outside [0, 1] the outer stops clamp.
Tip: for smooth gradients, space stops by perceptual distance, not numeric distance. Two close stops in dark regions look smoother than the same stops evenly placed across the full range.
The 🎲 Random button (top of the Color Stops section) generates a complete theme in one click — not just the palette. It always builds a fresh set of colour stops via a golden-ratio hue walk (maximally-spaced hues so no two stops crowd the wheel), then layers on extra randomized settings chosen by the current Kind and by the toggle row directly beneath the button.
| Area | When |
|---|---|
| Colour stops | Always. |
| Interpolation (Space / Curve / Transfer / Strength / Gamma) | When Interpolation is ticked (default on). |
| Cycle settings (offset / density / speed / wrap mode) | Every Kind except Gradient. |
| 3D light rig + shared Steepness / Ambient | Phong3D and Pbr3D. |
| Phong extras (key/fill/rim spec + diff scales) | Phong3D only. |
| PBR lighting mode, glow, and material bands | Pbr3D only. |
| In-set (interior) colour | When In-set is ticked (default on). |
| Post-FX defaults (Brightness / Contrast / Adaptive-HE) | When Post-FX is ticked (default off). |
| Control | Default | Effect |
|---|---|---|
| Random Experimental | off | Off = artful mode: every value stays inside a logical range, and 3D light colours + the in-set colour are pulled from the palette just generated so the result reads as one family. On = experimental mode: caps are removed and the generator "goes wild" — full-range colours, wider counts, unconstrained placement. |
| In-set | on | Include a random interior colour. Artful mode picks a dark member of the palette family (opaque) so the in-set reads as a recessed pocket; experimental mode allows any colour and any alpha. |
| Post-FX | off | Include random Post-FX defaults. Ticking this also ticks the Brightness / Contrast / Adaptive Use checkboxes to match (and unticking clears them) so you never have to flip them by hand. Artful mode keeps Brightness/Contrast within ±20 and Adaptive-HE under 50; experimental mode uses the full slider ranges. |
| Interpolation | on | Include random Space / Curve / Transfer / Transfer-strength / Palette-gamma. Artful keeps strength and gamma near neutral; experimental spans their full ranges. |
- Every click records the seed used in the Description field and writes it into the Seed field.
- Use Seed (default off): while off, the Seed field is greyed out and each click draws a fresh seed — so repeated clicks keep producing new themes. Tick Use Seed to enable the field; the next click uses the value you enter.
- The same seed with the same toggles, Kind, and Experimental state reproduces an identical theme. A single seeded RNG drives every step in fixed order, so changing any of those inputs changes the result.
Tip
Found a random theme you like? Its seed is already in the Seed field and the Description. Tick Use Seed, then flip Random Experimental on and off (or switch Kind) to explore controlled variations around the same starting point.
Note
Randomize replaces the current stops and the settings it covers. Untick a scope toggle (In-set, Post-FX, Interpolation) to protect those sections from being overwritten.
Active for Cycling / Phong3D / Pbr3D kinds.
Speed = 0.02 ≈ one full gradient cycle every 50 smoothed-iter units. Higher speed = more bands, tighter rings. Typical range 0.005 – 0.2.
For Phong3D + Pbr3D, the cycle controls the base albedo banding only — the lighting overlays on top, so a moderate cycle (0.02–0.05) usually reads better than a frantic high cycle.
Shared parameters between Phong3D and Pbr3D kinds:
| Parameter | Purpose | Typical range |
|---|---|---|
| Steepness | Z-scale on the synthesized normal. Higher = more relief depth. | 0.5 – 4.0 |
| Ambient | Base illumination before lighting. 0 = pitch-black shadows. | 0.0 – 0.3 |
Each light carries:
| Field | Description |
|---|---|
| Direction (X, Y, Z) | Normalised direction vector. (0, 0, 1) = straight at camera. |
| Diffuse RGB | Color of the diffuse contribution. Bright key, dim fill is typical. |
| Specular RGB | Color of the highlight. White / warm for key, cool for fill. |
| Shininess | Specular exponent. 1 = matte, 256 = chrome. |
Key Light is the strong, often warm primary. Fill Light is the dim, often cool sim of sky / bounce. Rim Light (optional) is a back-light that highlights silhouette edges.
A balanced 3-point setup: Key 1.0 / Fill 0.4 / Rim 0.3.
Phong3D exposes five per-light scale factors on top of the shared 3D-lighting block, letting you dial each light's diffuse / specular contribution independently for atmospheric accent (e.g., a cyan fill halo opposite the warm key spec).
| Field | Purpose | Typical range |
|---|---|---|
| Key spec | Specular strength of the Key light. | 0.4 – 1.2 |
| Fill spec | Specular strength of the Fill light. | 0.1 – 0.5 |
| Fill diff | Diffuse strength of the Fill light. | 0.2 – 0.6 |
| Rim spec | Specular strength of the Rim light (only when Rim is enabled). | 0.5 – 1.5 |
| Rim diff | Diffuse strength of the Rim light (only when Rim is enabled). | 0.1 – 0.4 |
Leave them near their defaults for a balanced rig; push a single value when you want one light to dominate.
Pbr3D uses a Cook-Torrance BRDF with a GGX normal-distribution function and Smith geometric occlusion. Material parameters drive the BRDF:
| Field | Purpose | Range |
|---|---|---|
| Lighting mode |
PBRRealistic (filmic curve) / PBRBright (pre-multiplied radiance for a punchier sci-fi look) |
enum |
| Glow exp / scale | Additive emission near escape (t → 1). | 0–10 / 0–5 |
| Material bands | List of (start t, end t, metallic, roughness) tuples. Lets you make the cardioid matte ceramic while the filaments turn chrome. |
per-band |
Material bands are evaluated in declared order — the first band whose (start, end) contains the current t wins. Out-of-range t falls back to a default (metallic 0, roughness 0.5).
When the Override checkbox is ticked, the picker sets the RGBA color for points that never escape (the cardioid + bulbs).
Default behavior (override off) draws the in-set with opaque black. Useful overrides:
- Dark navy
(8, 12, 32)to keep contrast without harshness. - Very-dark hue-matched color taken from the gradient's tail — keeps the in-set from popping visually.
- A partial alpha — the interior alpha is honored (per-theme, #96): below 255 the in-set composites over the 2D interior background, and the global
InteriorAlphaknob multiplies this value. The swatch previews the authored alpha so a translucent interior reads as faded.
Per-theme defaults for the three Post-FX sliders.
When you select this theme from a combo, the renderer snaps each slider to the corresponding default — unless that slider's Lock checkbox is ticked. Locking lets you preserve a global brightness preference across theme browsing.
| Field | Range | Default |
|---|---|---|
| Brightness | −100 … +100 | 0 |
| Contrast | −100 … +100 | 0 |
| Adaptive | 0 … 100 | 0 |
| Action | Behavior |
|---|---|
| Live preview | Edits push to the main render via 150 ms debounce. Drag freely; the calculator re-runs once per debounced commit. |
| Apply | Force a push regardless of live-preview state. |
| New Blank | Discard edits; start from a fresh Gradient (2 stops, black → white). |
| Revert | Reload from the last source theme name. |
| Save to Library | Validate Name + ≥ 2 stops, upsert into colorthemes.json. Prompts to confirm overwrite if the name already exists. |
| Export JSON… | Write a single-theme JSON array to disk. |
| Save C#… | Write a compilable ColorThemeData C# class via ColorThemeCsExporter. Drop the file into Models/ColorSchemes/Generated/ and rebuild to ship as built-in. |
| From Image… | Open the Image Palette helper. |
Sample any PNG / JPG / BMP, get a 5-stop palette via k-means clustering in CIELAB color space, loaded straight into the Color Stops list.
| Control | Purpose |
|---|---|
| Source image | Click to browse. Loads + downsamples for analysis. |
| Cluster count | 2 – 16 centroids. Default 5. |
| Sort | By hue / by lightness / by frequency. |
| Sample bias | Center / Edges / Uniform — bias which pixels feed the kmeans. |
| Use as palette | Load the centroids as Color Stops. |
Tip: pick a source image whose mood matches your fractal target. A sunset photo for a warm Mandelbrot, a CT scan for a sci-fi Mandelbulb.
Each entry in colorthemes.json is a single ColorThemeData object. Field omission follows WhenWritingNull — null fields disappear entirely.
{
"name": "My Theme",
"kind": "Phong3D",
"category": "Custom",
"description": "Warm dusk shading",
"maxZoom": 1e20,
"stops": [
{ "position": 0.0, "r": 8, "g": 4, "b": 16 },
{ "position": 0.4, "r": 255, "g": 80, "b": 16 },
{ "position": 1.0, "r": 255, "g": 230, "b": 180 }
],
"cycleSpeed": 0.03,
"lighting": {
"steepness": 1.6,
"ambient": 0.12,
"keyLight": {
"dir": { "x": 0.4, "y": 0.6, "z": 0.7 },
"diffuse": { "r": 1.0, "g": 0.9, "b": 0.8 },
"specular": { "r": 1.0, "g": 1.0, "b": 1.0 },
"shininess": 64
},
"fillLight": { ... },
"rim": null
},
"inSet": null,
"postFxDefaults": {
"brightness": 0,
"contrast": 10,
"adaptive": 0
}
}Pbr3D entries add a pbrExtras block with lightingMode, glowExp, glowScale, and a materialBands array.
Colour options (optional, all kinds). Omit for the historical look:
| Field | Values | Default | Effect |
|---|---|---|---|
interpolationSpace |
Srgb / OkLab / Hsv
|
Srgb |
Colour space the gradient blends stops in. OkLab = perceptually smooth mid-tones; Hsv = shorter-arc hue sweep. Zero render cost (baked into the LUT). |
interpolationCurve |
Linear / Cosine / Cubic / Step
|
Linear |
Segment blend shape. Cosine eases at both stops; Cubic = Catmull-Rom spline through stops (sRGB); Step = hard bands. |
transferFunction |
Linear / Sqrt / Cubic / Log / Sine
|
Linear |
Remaps the mapping scalar before lookup (Ultra-Fractal "transfer"). Log/Sqrt spread deep detail; Cubic compresses shadows. Gradient + Cycling only. |
transferStrength |
float [0,1]
|
1 |
Blends identity↔transferFunction. |
paletteGamma |
float [0.2,3]
|
1 |
Per-theme gamma baked into the LUT (out = in^(1/gamma)). >1 lifts shadows/brightens, <1 darkens. Zero render cost; compounds with the live image-gamma slider. |
colorOffset |
float | 0 |
Phase rotation of the palette along the iteration axis (Cycling / Phong3D / Pbr3D). |
colorDensity |
float | 1 |
Frequency multiplier — how many cycles fit, independent of cycleSpeed. |
wrapMode |
Repeat / PingPong / Clamp
|
Repeat |
Boundary behaviour. PingPong mirrors so there is no 1→0 seam. |
Each entry in stops also accepts an optional midpoint (float in (0,1),
default 0.5): the blend midpoint of the segment starting at that stop.
Values below 0.5 push the halfway colour toward this stop, above 0.5 toward the
next. Omit (or 0.5) for a straight blend.
- Kind: Gradient
- Stops: (0.0, #0A0613) → (0.3, #4B1B30) → (0.6, #C8521C) → (0.85, #FFA13C) → (1.0, #FFE9A8)
- In-set: override #050308.
- Kind: Cycling
- Cycle Speed: 0.025
- Stops: (0.0, #050E2B) → (0.4, #1E5780) → (0.7, #C0E6FF) → (1.0, #FFFFFF)
- Kind: Cycling
- Cycle Speed: 0.04
- Stops: (0.0, #1A0033) → (0.5, #FF5599) → (1.0, #FFFF99)
- Kind: Phong3D
- Cycle Speed: 0.03
- Stops: (0.0, #100000) → (0.45, #C04000) → (0.85, #FFC050) → (1.0, #FFFFE0)
- Steepness 2.2, Ambient 0.08
- Key Light dir (0.5, 0.6, 0.6), diffuse (1.0, 0.85, 0.55), spec (1.0, 1.0, 1.0), shine 96
- Fill Light dir (-0.4, -0.3, 0.5), diffuse (0.2, 0.3, 0.6), spec (0.4, 0.5, 0.8), shine 32
- Kind: Pbr3D
- Cycle Speed: 0.02
- Stops: (0.0, #110804) → (0.5, #C57033) → (1.0, #FFD79A)
- Lighting mode: PBRRealistic
- Material bands: [(0.0, 0.5, metallic 1.0, roughness 0.4), (0.5, 1.0, metallic 1.0, roughness 0.18)]
- Glow exp 6.0, scale 0.4
- Kind: Pbr3D
- Stops: (0.0, #050505) → (1.0, #FFFFFF)
- Material bands: [(0.0, 1.0, metallic 1.0, roughness 0.05)]
- Kind: Gradient with HSV-cycling color stops (12 stops around the hue wheel)
- In-set: override #000000.
- Stops: (0.0, #000000) → (0.5, #003B00) → (1.0, #6CFFB1)
- Post-FX defaults: contrast +20, brightness -10.
- Kind: Cycling
- Cycle Speed: 0.05
- Stops: (0.0, #E63946) → (0.5, #F1FA8C) → (1.0, #1D3557)
- Stops: (0.0, #000004) → (0.25, #420A68) → (0.5, #932667) → (0.75, #DD513A) → (1.0, #FCFFA4)
- Stops: (0.0, #FFC4D6) → (0.5, #C4B5FF) → (1.0, #B8F0FF)
- Cycle Speed: 0.03
- Kind: Cycling
- Cycle Speed: 0.08
- Stops: (0.0, #2E512E) → (0.4, #5A8C39) → (0.7, #C9B780) → (1.0, #FFFFFF)
- Repeats every ~12 iter units; reads like elevation rings.
- Kind: Cycling
- Cycle Speed: 0.06
- Stops: 6 stops cycling through magenta → blue → green → yellow → red → magenta.
- Kind: Pbr3D
- Stops: (0.0, #00111A) → (0.5, #00B0E0) → (1.0, #80FFFF)
- Material bands: [(0.0, 1.0, metallic 0.6, roughness 0.25)]
- Glow exp 4.0, scale 1.2
- Stops: (0.0, #2A1505) → (0.6, #A07550) → (1.0, #F0E0C0)
- Post-FX defaults: contrast +5.
- Kind: Phong3D
- Cycle Speed: 0.025
- Stops: (0.0, #051F3B) → (0.5, #7EB5E0) → (1.0, #FFFFFF)
- Steepness 1.8, Ambient 0.15
- Kind: Pbr3D
- Stops: (0.0, #050505) → (0.7, #4B0010) → (1.0, #FF7050)
- Material bands: [(0.0, 0.7, metallic 0.0, roughness 0.6), (0.7, 1.0, metallic 0.0, roughness 0.05)]
- Glow exp 3.0, scale 0.8
- Stops: (0.0, #F4E9DC) → (0.5, #B8D8E5) → (1.0, #D4A5A5)
- Post-FX defaults: brightness +10.
- Kind: Cycling
- Cycle Speed: 0.07
- Stops: 4 stops (#000033 → #6633CC → #CC33FF → #FFFFFF) repeated.
- Pair with Adaptive = 80 for psychedelic deep-zooms.
- Stops: (0.0, #FFFFFF) → (0.5, #777777) → (1.0, #000000)
- Cycle Speed: 0.04
- Useful for distance-estimation maps where shape, not color, is the goal.
Live preview lagging. Lower Cycle Speed temporarily, or untick Live preview and use Apply between edits.
Banding visible at deep zoom. Increase iteration count (Floating Menu → Iter), or raise Quality. The palette only colors what the calculator computes; bands appear when iter is too low for the depth.
Phong3D looks plastic. Drop Specular RGB and raise Roughness — actually, switch to Pbr3D and use the material band system. Phong's specular model lacks the energy conservation that makes PBR materials look ""real.""
Pbr3D too dark. Raise Ambient to 0.15–0.2, switch Lighting mode to PBRBright, or push the glow scale.
In-set color washes out the rest. Untick the override; the default opaque-black tends to read better. If you must override, pick a desaturated low-luma color.
Save button silently overwrites. As of v0.6.2, the overwrite confirmation prompt prevents accidental clobbering. If you're not seeing the prompt, the typed name doesn't match any existing user theme — Save proceeds as an insert.
My theme disappears after reload. Built-in themes don't write to colorthemes.json; only user-saved themes do. Use Save to Library, not Export JSON, for persistence.
Image Palette returns washed-out colors. Bias toward Edges or pick a more saturated source image. K-means clusters in CIELAB; pure-grey source images give a grey palette.
Color Theme Editor Guide · Fracturing Fog · © 2026