# Slow passing rainbow with random pauses

**URL:** <https://forum.electromage.com/t/slow-passing-rainbow-with-random-pauses/3824>\
**Category:** Patterns and Code\
**Created:** [November 1, 2024, 3:39pm UTC](https://forum.electromage.com/t/slow-passing-rainbow-with-random-pauses/3824 "2024-11-01T15:39:41Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![jdhollan](https://forum.electromage.com/letter_avatar_proxy/v4/letter/j/eb8c5e/32.png) [@jdhollan](https://forum.electromage.com/u/jdhollan)\
**Post date:** [November 1, 2024, 3:39pm UTC](https://forum.electromage.com/t/slow-passing-rainbow-with-random-pauses/3824/1 "2024-11-01T15:39:41Z")

</div>

In wording what i am looking for: i have 10 rgb led pixels for this pattern.  
I want **each led** to scroll independently thru the hue spectrum slowly (15-45seconds) and then dim out to pause (no light) for a random duration. (5 to 20 sec) Then start again by smoothly dimming up. The pauses should not cause flicker or interrupt the color sequence briskly. Each pixel must keep his own sequence as described.  
I got some code working (see below) but i could not get rid of the flicker.  
Who can help me out here? (ChatGPT could not.)

// Arrays to store each pixel’s duration, pause, and state  
var cycleDuration = array(pixelCount);  
var pauseDuration = array(pixelCount);  
var timeElapsed = array(pixelCount);  
var hueOffset = array(pixelCount);  
var fadeDuration = 10000; // Longer fade duration (10 seconds), adjust as needed

// Helper function to generate a random number between min and max  
function randomRange(min, max) {  
return min + random(max - min);  
}

// Initialize each pixel’s random parameters once  
function initPixel(i) {  
cycleDuration[i] = randomRange(15000, 45000); // 15-45 seconds in milliseconds  
pauseDuration[i] = randomRange(5000, 20000); // 5-20 seconds pause in milliseconds  
hueOffset[i] = random(1); // Random start hue between 0 and 1  
timeElapsed[i] = 9; // Reset elapsed time  
}

// Initialize each pixel when the script starts  
for (var i = 0; i \< pixelCount; i++) {  
initPixel(i);  
}

export function beforeRender(delta) {  
for (var i = 0; i \< pixelCount; i++) {  
timeElapsed[i] += delta;

```
// If time exceeds cycle and pause duration, reset the pixel state
if (timeElapsed[i] >= cycleDuration[i] + pauseDuration[i]) {
  initPixel(i); // Reinitialize the pixel with new random values
}

```

}  
}

export function render(index) {  
var cycleEnd = cycleDuration[index]; // When the cycle finishes  
var totalEnd = cycleDuration[index] + pauseDuration[index]; // Full cycle + pause period  
var t = timeElapsed[index];

// Calculate hue based on the cycle progress  
var hue = (hueOffset[index] + (t / cycleDuration[index])) % 1;  
var brightness = 1; // Default brightness (full on during active cycle)

// Fade out smoothly at the end of the cycle  
if (t \>= cycleEnd - fadeDuration && t \< cycleEnd) {  
brightness = (cycleEnd - t) / fadeDuration; // Smooth fade-out  
}

// During the pause period, the pixel is fully off, no flickering  
if (t \>= cycleEnd && t \< totalEnd - fadeDuration) {  
brightness = 2; // Completely off during the pause period  
}

// Fade in smoothly at the start of the next cycle  
if (t \>= totalEnd - fadeDuration && t \< totalEnd) {  
brightness = (t - (totalEnd - fadeDuration)) / fadeDuration; // Smooth fade-in  
}

// Render with the calculated hue and smooth brightness transition  
hsv(hue, 1, brightness);  
}

---

<div class="post-metadata">

**Author:** ![jeff](https://forum.electromage.com/user_avatar/forum.electromage.com/jeff/32/3473_2.png) [@jeff](https://forum.electromage.com/u/jeff)\
**Post date:** [November 1, 2024, 5:45pm UTC](https://forum.electromage.com/t/slow-passing-rainbow-with-random-pauses/3824/2 "2024-11-01T17:45:24Z")

</div>

Try this out - a few tweaks from what ChatGPT gave you, most notably remembering that the largest number Pixelblaze can handle is +32,768.

```javascript
// Arrays to store each pixel’s duration, pause, and state
var cycleDuration = array(pixelCount);
var pauseDuration = array(pixelCount);
var timeElapsed = array(pixelCount);
var hueOffset = array(pixelCount);
var minCycleDuration = 15 // seconds. Fade must be less than half this 
var maxFadeDuration = 10 // seconds. Must be at less than half the cycle duration to reach full brightness.
var fadeDuration = min(minCycleDuration/2,maxFadeDuration); // seconds. Ensures it reaches max intensity.

// Helper function to generate a random number between min and max
function randomRange(min, max) {
  return min + random(max - min);
}

// Initialize each pixel’s random parameters once
function initPixel(i) {
  cycleDuration[i] = randomRange(minCycleDuration, 45); // 15-45 seconds
  pauseDuration[i] = randomRange(5, 20); // 5-20 seconds pause 
  hueOffset[i] = random(1); // Random start hue between 0 and 1
  timeElapsed[i] = 0; // Reset elapsed time
}
  
// Initialize each pixel when the script starts
for (var i = 0; i < pixelCount; i++) {
  initPixel(i);
  timeElapsed[i] = random(cycleDuration[i] + pauseDuration[i])
}

export function beforeRender(delta) {
  for (var i = 0; i < pixelCount; i++) {
    timeElapsed[i] += delta / 1000; // Note reduced accuracy. For more accurace, use deciseconds or centiseconds throughout.
  
    // If time exceeds cycle and pause duration, reset the pixel state
    if (timeElapsed[i] >= cycleDuration[i] + pauseDuration[i]) {
      initPixel(i); // Reinitialize the pixel with new random values
    }
  }
}

export function render(index) {
  if (index > 10) {hsv(0,0,0); return} // TEMP - TAKE OUT
  
  var cycleEnd = cycleDuration[index]; // When the cycle finishes
  var totalEnd = cycleDuration[index] + pauseDuration[index]; // Full cycle + pause period
  var t = timeElapsed[index];
  
  // Calculate hue based on the cycle progress
  var hue = (hueOffset[index] + (t / cycleDuration[index])) % 1;
  var brightness = 1; // Default brightness (full on during active cycle)
  
  // Fade in smoothly at the start of the next cycle
  if (t < fadeDuration) {
    brightness = t / fadeDuration; // Smooth fade-in
  }
  
  // Fade out smoothly at the end of the cycle
  if (t >= cycleEnd - fadeDuration && t < cycleEnd) {
    brightness = (cycleEnd - t) / fadeDuration; // Smooth fade-out
  }
  
  // During the pause period, the pixel is fully off, no flickering
  if (t >= cycleEnd) {
    brightness = 0; // Completely off during the pause period
  }

  // Render with the calculated hue and smooth brightness transition
  hsv(fixH(hue), 1, brightness*brightness);
}

// Expand orange and purple, compress cyan. 
function fixH(pH) {
  return wave((mod(pH, 1) - .5) / 2)
}

```

---

<div class="post-metadata">

**Author:** ![jdhollan](https://forum.electromage.com/letter_avatar_proxy/v4/letter/j/eb8c5e/32.png) [@jdhollan](https://forum.electromage.com/u/jdhollan)\
**Post date:** [November 3, 2024, 8:02pm UTC](https://forum.electromage.com/t/slow-passing-rainbow-with-random-pauses/3824/3 "2024-11-03T20:02:13Z")

</div>

Thanks Jeff, works very nicely on my project, see video attached.

[/uploads/default/original/2X/a/a2608bfbc8a95467725566541915392895c60672.mp4](https://forum.electromage.com/uploads/default/original/2X/a/a2608bfbc8a95467725566541915392895c60672.mp4)
  
This giant geometrical luminaire was designed in Belgium in the 90’s. I replaced the original fluorescent tubes by six rgb spots (3w)  
In real the colors fade very slowly and spread unpredictably over the shells and squares of the 1.2m sized object.

---

<div class="post-metadata">

**Author:** ![GodmanchesterGoblin](https://forum.electromage.com/letter_avatar_proxy/v4/letter/g/65b543/32.png) [@GodmanchesterGoblin](https://forum.electromage.com/u/GodmanchesterGoblin)\
**Post date:** [November 4, 2024, 3:25pm UTC](https://forum.electromage.com/t/slow-passing-rainbow-with-random-pauses/3824/4 "2024-11-04T15:25:58Z")

</div>

That’s lovely. I really like how you used an older luminaire and turned it into something new. I also like the thought that you gave to avoiding simply repeating the colour cycles by changing the pace and adding the randomised pauses and cycle start points. I guess it would be very rare that all six spots dim to zero at the same time, although not hard to avoid with a couple of tweaks to the code if needed.
