Files
havox/projects/tsp/index.html
2026-03-21 15:05:08 +00:00

108 lines
3.2 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Travelling Salesman Problem</title>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<div class="container">
<a href="/#projects" class="back-button">← Back</a>
<header>
<h1>Travelling Salesman Problem</h1>
<p class="subtitle">
An interactive route visualiser built with WebGL and WebAssembly.
</p>
</header>
<section>
<p>
After writing one of my first tutorials on the Travelling Salesman
Problem, I wanted to revisit it with a slightly more technical stack.
The backend is written in Zig (compiled to WebAssembly), and the
rendering is done directly in WebGL instead of p5.js or Raylib.
</p>
<p>
This project was also inspired by
<a href="https://www.youtube.com/@sphaerophoria">sphaerophoria</a> who
started a
<a
href="https://www.youtube.com/watch?v=RiLjPBci6Og&list=PL980gcR1LE3L8RoIMSNBFfw4dFfS3rrsk"
>series</a
>
on creating his own map.
</p>
<div class="info-box">
<p>
Drag points around the canvas and watch the route update in real
time.
</p>
</div>
</section>
<div class="canvas-container">
<div class="canvas-toolbar">
<div class="control-group" aria-label="TSP controls">
<label for="pointCountInput">Points</label>
<input
id="pointCountInput"
type="number"
min="5"
max="100"
step="1"
value="36"
/>
<button
id="applyPointCountButton"
class="action-button"
type="button"
>
Regenerate
</button>
</div>
</div>
<div class="canvas-shell">
<canvas
id="tsp-canvas"
aria-label="Travelling Salesman Problem canvas"
>
HTML5 canvas not supported in browser
</canvas>
</div>
<div class="status-row">
<div id="pointCountStatus" class="status">36 points</div>
<p class="canvas-note">
Tip: click and drag a point to recompute the route.
</p>
</div>
</div>
<section>
<h3>Technical Details</h3>
<p>
The backend is written in Zig, and the route is built in two passes: a
nearest-neighbour pass followed by a 2-opt local search.
</p>
<p>
Point coordinates are stored in WebAssembly memory, and the route
order is recalculated whenever the layout changes. Rendering is
handled in WebGL to keep interaction smooth as the point count
increases.
</p>
</section>
<footer>
<p>Built with Zig, WebGL2 and WebAssembly</p>
</footer>
</div>
<script src="./point.js"></script>
<script type="module" src="./main.js"></script>
</body>
</html>