In my post yesterday, on building a color palette utility in Alpine.js, randomness played a big part: each swatch was generated as a composite of randomly selected Hue `(0..360)`

, Saturation (`0..100`

), and Lightness (`0..100`

) values. As I was putting that demo together, I came across the Web Crypto API. Normally, when generating random values, I use the the `Math.random()`

method; but, the MDN docs mention that `Crypto.getRandomValues()`

is more secure. As such, I ended up trying `Crypto`

out (with a fallback to the `Math`

module as needed). But, this left me wondering if “more secure” actually meant “more random” for my particular use-case.

**Run this demo** in my **JavaScript Demos project** on GitHub.

**View this code** in my **JavaScript Demos project** on GitHub.

Randomness, from a security standpoint, has an actual meaning. I’m not a security expert; but, my understanding is that when a pseudo-random number generator (PRNG) is considered “secure”, it means that the sequence of numbers that it will produce—or has already produced—cannot be deduces by an attacker.

When it comes to “random color generators”, like my color palette utility, the notion of “randomness” is much more fuzzy. In my case, the random color generation is only as random as is “feels” to the user. In other words, the effectiveness of the randomness is part of the overall user experience (UX).

To this end, I want to try generating some random *visual* elements using both `Math.random()`

and `crypto.getRandomValues()`

to see if one of the methods *feels* substantively different. Each trial will contain a randomly generated ` element and a randomly generated set of integers. Then, I will use my (deeply flawed) human intuition to see if one of the trials looks “better” than the other.`

The `Math.random()`

method works by returning a decimal value between `0`

(inclusive) and `1`

(exclusive). This can be used to generate random integers by taking the result of the randomness and multiplying it against a range of possible values.

In other words, if `Math.random()`

returned `0.25`

, you’d pick the value that lands closest to 25% along the given min-max range. And, if `Math.random()`

returned `0.97`

, you’d pick the value that lands closest to 97% along the given min-max range.

The `crypto.getRandomValues()`

method works very differently. Instead of returning a single value, you pass-in a Typed Array with a pre-allocated size (length). The `.getRandomValues()`

method then fills that array with random values dictated by the min/max values that can be stored by the given Type.

To make this exploration easier, I want both approaches to work roughly the same. So, instead of having to deal with decimals in one algorithm and integers in another algorithm, I’m going to force both algorithms to rely on decimal generation. Which means, I have to coerce the `value`

returned by `.getRandomValues()`

into a decimal (`0..1`

):

`value / ( maxValue + 1 )`

I’ll encapsulate this difference in two method, `randFloatWithMath()`

and `randFloatWithCrypto()`

:

```
/**
* I return a random float between 0 (inclusive) and 1 (exclusive) using the Math module.
*/
function randFloatWithMath() {
return Math.random();
}
/**
* I return a random float between 0 (inclusive) and 1 (exclusive) using the Crypto module.
*/
function randFloatWithCrypto() {
var [ randomInt ] = crypto.getRandomValues( new Uint32Array( 1 ) );
var maxInt = 4294967295;
return ( randomInt / ( maxInt + 1 ) );
}
```

With these two methods in place, I can then assign one of them to a `randFloat()`

reference which can be used to seamless generate random values along a given range using either algorithm interchangeably:

```
/**
* I generate a random integer in between the given min and max, inclusive.
*/
function randRange( min, max ) {
return ( min + Math.floor( randFloat() * ( max - min + 1 ) ) );
}
```

Now to create the experiment. The user interface is small and is powered by Alpine.js. Each trial uses the same Alpine.js component; but, its constructor receives an argument that determines which `randFloat()`

implementation will be used:

```
```
##
Math Module

Duration:

##
Crypto Module

Duration: ms