Animate randomly-generated art with Rust + WebAssembly.
The patterns generated by Spectrum are inspired by my submission to CS 225's MP1 Part 3, which invovles using the HSL color space to generate artwork.
Spectrum uses three different rendering methods:
- WebGL + WebAssembly
- WebAssembly only (
2d
canvas rendering context) - JavaScript only (
2d
canvas rendering context)
This originated as a way for me to test out Rust with WebAssembly, but after seeing the limitations of a CPU-only render (the WebAssembly-only implementation), I decided to try out implementing the same logic in WebGL to better understand the benefits of GPU-accelerated rendering. To illustrate the benefits of WebAssembly, I also created the JavaScript-only implementation as a comparison.
For a given canvas, a number of "sources" are assigned. Each source is assigned a random position (x, y) that falls within the canvas, and a random hue value in the HSL color space. Every pixel in the canvas is colored according to a weighted average of distance from each source, using the inverse squared distance from each source as the weighting factor (with a small constant added value to avoid dividing by zero).
However, as hue is a periodic/circular metric, weighting by mean will yield incorrect results. For example (in degrees), the mean of hues 10 and 350 will be 180, while the actual average hue will be 0. To account for this, each source's hue is broken in to sine and cosine components which are summed to reach a total. The arctangent is then applied to the total to calculate the resulting hue.
The formula for calculating the hue of a pixel is as follows:
The saturation and lightness are held to be 100% and 50%, respectively, to get the purest form of the hue. The resulting HSL is converted to the RGB color space to set the color of the pixel.
Spectrum requires that you have the Rust default toolchain and Node.js installed. Additionally, wasm-pack is also required to build and package the WebAssembly.
Build and package the WebAssembly using the wasm-pack
script:
npm run wasm-pack
Install NPM dependencies using npm install
: (note: this requires the wasm-pack
script to have been run as the results are marked as a local dependency)
npm install
Start the application for local development using npm start
:
npm start
Build and bundle the application to the dist
directory using the build
script:
npm run build
Serve files from the dist
directory using the serve
script: (note: requires the build
script to have been run to generate the dist
directory):
npm run serve
Minify index.html
and spectrum.css
: (note: requires the build
script to have been run to generate the dist
directory):
npm run minify
Format files or check for formatting compliance with the format
and format:check
scripts, respectively:
npm run format
npm run format:check
Check for lint errors or fix them with the lint
and lint:fix
scripts, respectively:
npm run lint
npm run lint:fix
Spectrum draws heavily from the following examples:
- A formula from the IEEE Signal Processing Magazine is also used as a faster alternative to Rust's standard library arctangent function
- The formula for converting between HSL and RGB is derived from RapidTables HSL to RGB color conversion.