Random gradient header generator
Please tell me about everything I could do better, but especially how to calculate and not hardcode the randomly shifted second array [...].


I suggest to get a random permutation of [0, 1, 2] by introducing a simple but unbiased shuffle function.

A circular shift of that random permutation can then be found by mapping index i to index (i + shift) % length:

// Return two shifted colors with min, max and random component:
function randomGradientColors(min, max) {
  let permutation = shuffle([0, 1, 2]);
  let shift = random(1, 2);
  return [
    permutation.map(i =&gt; [min, max, random(min, max)][i]),
    permutation.map(i =&gt; [min, max, random(min, max)][(i + shift) % 3])
  ];
}


Since you asked for everything that you could do better, I would like to suggest using a CSS background gradient instead of a canvas element. If compatibility is not a concern, you can even leverage fancy CSS variables:

.gradient {
  background: linear-gradient(90deg, var(--from, black), var(--to, black));
}


Your markup then would provide the min and max color components via data attributes:

&lt;div class="gradient" data-min="70" data-max="185"&gt;&lt;/div&gt;


And your script would simply query all .gradient elements and compute their CSS from and to variables from the provided data attributes:

let gradients = document.querySelectorAll(".gradient");
for (let gradient of gradients) {
  let [from, to] = randomGradientColors(
    gradient.dataset.min,
    gradient.dataset.max
  );
  gradient.style.setProperty("--start", "rgb(" + from + ")");
  gradient.style.setProperty("--to", "rgb(" + to + ")");
}


This approach is pretty flexible and allows you to adapt the styling to your needs without touching the script.

Here is the complete code:



// Return random integer within interval [min, max]:
function random(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

// Shuffle array in-place:
function shuffle(array) {
  for (let i = array.length - 1; i &gt; 0; i--) {
    let j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}

// Return two shifted colors with min, max and random component:
function randomGradientColors(min, max) {
  let permutation = shuffle([0, 1, 2]);
  let shift = random(1, 2);
  return [
    permutation.map(i =&gt; [min, max, random(min, max)][i]),
    permutation.map(i =&gt; [min, max, random(min, max)][(i + shift) % 3])
  ];
}

// Compute CSS 'from' and 'to' variables for all gradients:
let gradients = document.querySelectorAll(".gradient");
for (let gradient of gradients) {
  let [from, to] = randomGradientColors(
    gradient.dataset.min,
    gradient.dataset.max
  );
  gradient.style.setProperty("--from", "rgb(" + from + ")");
  gradient.style.setProperty("--to", "rgb(" + to + ")");
}
html {
  background-color: #1d1f21;
}

.gradient {
  display: inline-block;
  width: 500px;
  height: 180px;
  background: linear-gradient(90deg, var(--from, black), var(--to, black));
}

.container {
  text-align: center;
}

.textbox {
  text-align: center;
  color: white;
  font-family: monospace;
}
&lt;div class="container"&gt;
  &lt;div class="gradient" data-min="70" data-max="185"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="textbox"&gt;Reload to get a different header gradient.&lt;/div&gt;




If you wish to support older browsers, remove the CSS variables and use

gradient.style.background = 
  "linear-gradient(90deg, rgb(" + from + "), rgb(" + to + "))";