Here’s one way of doing it – this pattern generates two random colors, usually fairly saturated, then fades slowly between them by doing linear RGB interpolation at a random per-channel rate. Transition time can be set by slider for between 0 and 15 seconds.

```
// Smooth, slow interpolation between random RGB colors, at random
// rate per channel.
//
// 2021 ZRanger1
// global variables and initialization
var frameTime = 0;
export var speed = 5000;
var r,g,b;
var rRate,gRate,bRate;
randomizeChannelRates();
var color1 = array(3);
randomRGB(color1);
var color2 = array(3);
randomRGB(color2);
// simple, quick HSV to RGB algorithm adapted from random GLSL
function hsvToRGB(h,s,v,rgbColor) {
var r,g,b,cv,k;
h *= 6;
k = v * s;
cv = 1-s; cv *=cv;
r = (h+5) % 6;
r = v - k * max(min(min(r,4-r),1),0);
g = (h+3) % 6;
g = v - k * max(min(min(g,4-g),1),0);
b = (h+1) % 6;
b = v - k * max(min(min(b,4-b),1),0);
rgbColor[0] = r;
rgbColor[1] = g;
rgbColor[2] = b;
}
// generate random RGB color, with a strong bias towards more
// saturated colors
function randomRGB(c) {
var h,s,v;
// generate the color as HSV, then convert. It's easier to control saturation
// that way.
h = random(1);
s = 1-(random(1) * random(1) * random(1) * random(1));
v = max(random(1),0.0125);
hsvToRGB(h,s,v,c);
}
// color fade time - 0 to 15 seconds
export function sliderSpeed(v) {
speed = 15000 * v;
}
// generate "normalized" per-channel change rates that we
// can use as simple multipliers
function randomizeChannelRates() {
var m;
rRate = random(1);
gRate = random(1);
bRate = random(1);
m = max(rRate,max(gRate,bRate));
rRate = 2 - rRate/m;
gRate = 2 - gRate/m;
bRate = 2 - bRate/m;
}
// linear interpolator.
function mix(start,end,val) {
val = min(1,val)
return start * (1-val) + end * val;
}
export function beforeRender(delta) {
pct = frameTime/speed;
frameTime += delta;
// calculate current color by linear interpolation
r = mix(color1[0],color2[0],pct * rRate);
g = mix(color1[1],color2[1],pct * gRate);
b = mix(color1[2],color2[2],pct * bRate);
// when we reach the end of a fade, generate
// new target color
if (frameTime > speed) {
color1[0] = color2[0];
color1[1] = color2[1];
color1[2] = color2[2];
randomRGB(color2);
randomizeChannelRates();
frameTime = 0;
}
}
export function render(index) {
rgb(r,g,b);
}
```