A small learning project that combines Rust, WebAssembly, TypeScript, and React to build a package that can "unsort" arrays in a few different ways.
This project is intentionally a little silly — it exists mostly as a hands-on way to learn how to:
- write reusable Rust code
- compile Rust to WebAssembly
- expose a clean JavaScript/TypeScript API from a Rust library
- wrap low-level WASM exports in a nicer React-friendly package
- build a real Vite + React demo app on top of the package
- add step-by-step visual tracing for algorithm playback
The result is a package that is easy to consume from React, while the heavy lifting happens in Rust.
react-unsorter-lib exposes two main functions for working with number arrays:
unsort()— returns a new array with the values rearranged using one of several algorithmsunsortSteps()— returns the final result plus a list of swap steps that can be replayed in a UI
Available algorithms:
FisherYates- uniformly shuffles the arraySattolo- creates one random cycle with no fixed points for arrays of length 2 or moreDerangement- shuffles until no element remains in its original positionRiffle- simulates a human-style packet interleaveInsideOut- builds a shuffled permutation incrementallyReverse- reverses the arrayFaroOutandFaroIn- perfectly interleave the two halvesBitReversal- reorders values by bit-reversed indicesRecursive- recursively rearranges halves of the arrayMask- uses a custom pseudo-random swap pattern
You can also pass an optional seed for the randomized algorithms to make results reproducible.
react-unsorter-lib/
├─ rust-unsorter/ # Rust crate compiled to WebAssembly
├─ wrapper/ # TypeScript package that wraps the WASM exports
└─ demo-app/ # React + Vite demo app
The Rust crate contains the actual algorithms and the WASM bindings. It exports the core unsort function, the unsortSteps trace function, and the Algorithm enum.
This is the ergonomic TypeScript package that application code imports. It hides the WASM-specific details and provides a nicer API for React and TypeScript consumers.
A small Vite + React app that shows the library in action with a polished visualizer, mode switching, playback controls, and bar highlighting.
The Rust/WASM layer is intentionally kept low-level. The wrapper makes the package nicer to use by:
- converting plain arrays to
Int32Arrayautomatically - providing TypeScript types for the public API
- exposing a simple import path for app code
- hiding WASM-specific details from the demo app
- normalizing the trace result so the UI can use it easily
That means React code can call the library like a normal package instead of dealing with the lower-level WASM export directly.
Make sure you have the following installed:
If you do not have wasm-pack yet, install it with:
cargo install wasm-packFrom the rust-unsorter directory:
cd rust-unsorter
wasm-pack build --target bundler --out-dir ../wrapper/pkgThis generates the WASM package inside wrapper/pkg, which is what the TypeScript wrapper imports.
From the wrapper directory:
cd wrapper
npm install
npm run buildThis compiles the TypeScript wrapper into dist/.
From the demo-app directory:
cd demo-app
npm install
npm run devThe demo app uses Vite, so it also needs the WASM plugin configured.
The demo app uses vite-plugin-wasm so Vite can load the generated WebAssembly package correctly.
The important part of the Vite config is:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import wasm from 'vite-plugin-wasm'
export default defineConfig({
plugins: [react(), wasm()],
optimizeDeps: {
exclude: ['react-unsorter-lib']
}
})The optimizeDeps.exclude entry helps Vite avoid pre-bundling the local WASM package in a way that can break loading.
import { unsort, Algorithm } from 'react-unsorter-lib';
const input = [1, 2, 3, 4, 5];
const output = unsort(input, {
algorithm: Algorithm.FisherYates,
seed: 123,
});
console.log(output); // Int32Arrayimport { unsortSteps, Algorithm } from 'react-unsorter-lib';
const trace = unsortSteps([1, 2, 3, 4, 5], {
algorithm: Algorithm.Reverse,
});
console.log(trace.result); // Int32Array
console.log(trace.steps); // swap steps for animationunsort(
input: number[] | Int32Array,
options?: {
algorithm?: Algorithm;
seed?: number;
}
): Int32ArrayunsortSteps(
input: number[] | Int32Array,
options?: {
algorithm?: Algorithm;
seed?: number;
}
): {
result: Int32Array;
steps: Array<{ kind: 'swap'; i: number; j: number }>;
}inputcan be either a regularnumber[]or anInt32Array- the result of
unsort()is returned as anInt32Array unsortSteps()returns both the final result and a list of swap operationsseedis optional and only matters for randomized algorithms
The demo app shows the library in a more polished UI:
- generate a sorted array
- choose an algorithm
- optionally set a seed
- switch between Instant and Step-by-step modes
- click Unsort for a fast result
- click Generate trace to replay the swaps visually
- use playback controls to pause, step once, reset, or change speed
- see the changed bars highlighted during playback
It is not meant to be a serious sorting visualizer. It is a learning demo that makes the WASM package easier to understand and test.
This project is a learning exercise, so the implementation focuses on clarity and experimentation rather than perfect production behavior.
A few things worth knowing:
- the Rust crate exports multiple algorithms through a single WASM interface
- the wrapper keeps the consumer API small and pleasant
- the demo app is there to prove the package works in a real React setup
- the project structure is split intentionally so each layer can be learned independently
- step tracing is implemented as a lightweight observer layer so the non-traced path stays clean
MIT
Built as a learning project for experimenting with Rust, WebAssembly, and React package design.
