Code/KelvinSpot.cs

A SpotLight subclass that exposes a color temperature (Kelvin) and brightness slider. It converts a Kelvin temperature to an sRGB Color and applies it multiplied by a brightness factor to the underlying SpotLight's LightColor.

using Sandbox;
using System;

namespace RotSoft;

/// <summary>
/// A Spotlight with a kelvin temperature gradient bar.
/// </summary>
public class KelvinTemperatureAttribute : System.Attribute { }

public sealed class KelvinSpot : SpotLight
{
    public new Color LightColor
    {
        get => base.LightColor;
        set => base.LightColor = value;
    }

    float _temperature = 5500f;

    [Property, Range(1000f, 20000f), Step(10f), KelvinTemperature]
    public float Temperature
    {
        get => _temperature;
        set
        {
            if (_temperature == value) return;
            _temperature = value;
            ApplyColor();
        }
    }

    float _brightness = 1f;

    [Property, Range(0.1f, 100f), Step(0.1f), Title("Brightness")]
    public float Range
    {
        get => _brightness;
        set
        {
            if (_brightness == value) return;
            _brightness = value;
            ApplyColor();
        }
    }

    void ApplyColor()
    {
        LightColor = KelvinToColor(_temperature) * _brightness;
    }

    /// <summary>
    /// Approximate kelvin → sRGB. Based on Tanner Helland's algorithm.
    /// </summary>
    public static Color KelvinToColor(float kelvin)
    {
        float temp = kelvin / 100f;
        float r, g, b;

        if (temp <= 66f)
            r = 1f;
        else
            r = Math.Clamp(1.29293618606f * MathF.Pow(temp - 60f, -0.1332047592f), 0f, 1f);

        if (temp <= 66f)
            g = Math.Clamp(0.390081578769f * MathF.Log(temp) - 0.63184144378f, 0f, 1f);
        else
            g = Math.Clamp(1.12989086369f * MathF.Pow(temp - 60f, -0.0755148492f), 0f, 1f);

        if (temp >= 66f)
            b = 1f;
        else if (temp <= 19f)
            b = 0f;
        else
            b = Math.Clamp(0.54320678911f * MathF.Log(temp - 10f) - 1.19625408914f, 0f, 1f);

        return new Color(r, g, b);
    }
}