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 (
2dcanvas rendering context) - JavaScript only (
2dcanvas 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-packInstall 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 installStart the application for local development using npm start:
npm startBuild and bundle the application to the dist directory using the build script:
npm run buildServe 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 serveMinify index.html and spectrum.css: (note: requires the build script to have been run to generate the dist directory):
npm run minifyFormat files or check for formatting compliance with the format and format:check scripts, respectively:
npm run format
npm run format:checkCheck for lint errors or fix them with the lint and lint:fix scripts, respectively:
npm run lint
npm run lint:fixSpectrum 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.
