Interactive visualizations of non-trivial algorithms, built to demonstrate computational geometry, graph theory, and optimization knowledge. Each algorithm is implemented from scratch in Go, compiled to WebAssembly, and rendered via the Canvas API with no visualization libraries.
Emphasis on correctness, clean architecture, and visual clarity. All algorithm logic is written in pure Go β no JS, no external dependencies on the logic layer.
- Go β all algorithm logic and WASM binaries
- WebAssembly β Go compiled to
.wasm, loaded in the browser - Vite β build tool and dev server for the JS shell
- TypeScript β thin JS shell for bootstrapping WASM and wiring the UI
- Canvas API β all rendering (no D3, no charting libraries)
- Tailwind CSS β styling
go testβ unit testing for all algorithm logic
algo-viz/
βββ go/ # all Go source
β βββ algorithms/ # pure algorithm logic β no syscall/js, no side effects
β β βββ voronoi/ # Fortune's Algorithm
β β βββ edmonds_karp/ # Maximum Flow
β β βββ simulated_annealing/ # Simulated Annealing for TSP
β β βββ kd_tree/ # KD-Tree + nearest neighbor
β β βββ aho_corasick/ # Aho-Corasick string matching
β βββ wasm/ # WASM entry points, one per algorithm
β β βββ voronoi/main.go # exposes JS-callable functions via syscall/js
β β βββ edmonds_karp/main.go
β β βββ simulated_annealing/main.go
β β βββ kd_tree/main.go
β β βββ aho_corasick/main.go
β βββ go.mod
βββ src/ # TypeScript shell
β βββ wasm/ # WASM loader + JS bindings per algorithm
β β βββ loader.ts # shared WASM instantiation helper
β β βββ voronoi.ts
β β βββ edmondsKarp.ts
β β βββ simulatedAnnealing.ts
β β βββ kdTree.ts
β β βββ ahoCorasick.ts
β βββ visualizers/ # canvas rendering, one file per algorithm
β β βββ VoronoiVisualizer.ts
β β βββ EdmondsKarpVisualizer.ts
β β βββ SimulatedAnnealingVisualizer.ts
β β βββ KdTreeVisualizer.ts
β β βββ AhoCorasickVisualizer.ts
β βββ components/ # shared UI
β β βββ AlgoCanvas.ts # canvas wrapper with resize handling
β β βββ Controls.ts # play/pause, speed, step, reset
β β βββ InfoPanel.ts # algorithm description + complexity
β β βββ Nav.ts # navigation between visualizers
β βββ pages/ # one entry point per algorithm
β β βββ voronoi.ts
β β βββ edmondsKarp.ts
β β βββ simulatedAnnealing.ts
β β βββ kdTree.ts
β β βββ ahoCorasick.ts
β βββ hooks/
β βββ animationLoop.ts # rAF loop abstraction
β βββ canvasResize.ts # ResizeObserver canvas scaling
βββ public/
β βββ wasm/ # compiled .wasm binaries (build output)
β βββ wasm_exec.js # Go's WASM runtime shim (copy from GOROOT)
βββ dist/ # Vite build output
βββ README.md
βββ index.html
βββ vite.config.ts
βββ tailwind.config.ts
βββ tsconfig.json
βββ build.sh # compiles all Go packages to WASM, then runs Vite
Go owns all logic. Files in go/algorithms/ must be pure Go β no syscall/js, no global state, no I/O. They receive input and return output. This makes them independently testable with go test and portable outside the browser.
WASM entry points are thin wrappers. Files in go/wasm/ import from go/algorithms/ and expose functions to JavaScript via syscall/js. They should contain no algorithm logic β only marshalling and JS bindings.
TypeScript is a shell, not a framework. The src/ layer loads WASM, wires up the canvas, and handles UI state. It does not reimplement any algorithm logic. Keep it minimal.
Visualizers own the canvas. Visualizer files receive a CanvasRenderingContext2D and algorithm state returned from WASM, and draw. They do not own animation timing β that belongs to animationLoop.ts.
| Algorithm | Category | Key Concepts |
|---|---|---|
| Fortune's Algorithm | Computational Geometry | Sweep line, beach line, parabolas, half-edge DCEL |
| Edmonds-Karp | Graph / Network Flow | BFS augmenting paths, residual graph, max-flow min-cut |
| Simulated Annealing (TSP) | Optimization | Probabilistic hill climbing, cooling schedule, combinatorial search |
| KD-Tree | Spatial Data Structures | Binary space partitioning, nearest neighbor, range search |
| Aho-Corasick | String Algorithms | Trie, failure links, finite automaton, multi-pattern matching |
Every visualizer must support:
- Play / Pause β start and freeze the animation at any point
- Step β advance exactly one logical step when paused
- Speed slider β control animation playback rate
- Reset β restore to initial state
- Randomize β generate new input (where applicable)
Go
gofmtenforced β no exceptions- Every exported function must have a doc comment
- Algorithm files must have a package-level comment explaining the algorithm, time complexity, and space complexity
- No
interface{}/anyin algorithm logic β use concrete types
TypeScript
- Strict mode enabled β no
any, no type assertions unless unavoidable - Keep the shell lean β if logic is creeping into TS, it belongs in Go
All algorithm logic in go/algorithms/ must have _test.go files. At minimum, test:
- Correctness on known inputs
- Edge cases (empty input, single point, degenerate cases)
cd go && go test ./...# compile all Go packages to WASM and copy to public/wasm/
./build.sh
# start Vite dev server (run build.sh first)
npm run dev
# production build
npm run build
# run Go tests
cd go && go test ./...Each Go package in go/wasm/ is compiled separately:
GOOS=js GOARCH=wasm go build -o public/wasm/voronoi.wasm ./go/wasm/voronoi/build.sh handles this for all five algorithms. wasm_exec.js must be copied from your local Go installation:
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" public/Deployed to Cloudflare via the unified Workers + Static Assets flow (the successor to classic Pages). Connects directly to the GitHub repo β pushes to main trigger automatic builds and deploys. Live demo link is pinned in the repo description.
Build settings in the Cloudflare dashboard:
- Build command:
./build.sh && npm run build - Deploy command:
npx wrangler deploy
Asset config lives in wrangler.toml ([assets] directory = "./dist"). Hash routing keeps every URL on /, so no SPA fallback is needed.
Note: Cloudflare's build image includes Go β no custom Docker image needed.