formatting

This commit is contained in:
Jay
2026-03-21 15:05:08 +00:00
parent 2100334f1f
commit 13c8b0a28e
26 changed files with 3176 additions and 2631 deletions

210
404.css
View File

@@ -1,171 +1,171 @@
body { body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100vh; min-height: 100vh;
} }
.not-found { .not-found {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
text-align: center; text-align: center;
padding: 7rem 2rem 5rem; padding: 7rem 2rem 5rem;
gap: 0; gap: 0;
position: relative; position: relative;
} }
.nf-code { .nf-code {
font-family: 'Fraunces', serif; font-family: "Fraunces", serif;
font-size: clamp(7rem, 22vw, 16rem); font-size: clamp(7rem, 22vw, 16rem);
font-weight: 600; font-weight: 600;
line-height: 1; line-height: 1;
color: var(--surface0); color: var(--surface0);
letter-spacing: -0.02em; letter-spacing: -0.02em;
user-select: none; user-select: none;
position: relative; position: relative;
opacity: 0; opacity: 0;
animation: fadeUp 0.6s 0.1s forwards; animation: fadeUp 0.6s 0.1s forwards;
} }
.nf-eyebrow { .nf-eyebrow {
font-size: 0.7rem; font-size: 0.7rem;
letter-spacing: 0.2em; letter-spacing: 0.2em;
text-transform: uppercase; text-transform: uppercase;
color: var(--mauve); color: var(--mauve);
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.75rem; gap: 0.75rem;
opacity: 0; opacity: 0;
animation: fadeUp 0.6s 0.3s forwards; animation: fadeUp 0.6s 0.3s forwards;
} }
.nf-eyebrow::before, .nf-eyebrow::before,
.nf-eyebrow::after { .nf-eyebrow::after {
content: ''; content: "";
display: block; display: block;
height: 1px; height: 1px;
width: 3rem; width: 3rem;
background: var(--mauve); background: var(--mauve);
opacity: 0.5; opacity: 0.5;
} }
.nf-heading { .nf-heading {
font-family: 'Fraunces', serif; font-family: "Fraunces", serif;
font-size: clamp(1.6rem, 4vw, 2.8rem); font-size: clamp(1.6rem, 4vw, 2.8rem);
font-weight: 600; font-weight: 600;
color: var(--text); color: var(--text);
line-height: 1.15; line-height: 1.15;
margin-bottom: 1rem; margin-bottom: 1rem;
opacity: 0; opacity: 0;
animation: fadeUp 0.6s 0.4s forwards; animation: fadeUp 0.6s 0.4s forwards;
} }
.nf-heading em { .nf-heading em {
font-style: italic; font-style: italic;
color: var(--mauve); color: var(--mauve);
} }
.nf-desc { .nf-desc {
font-size: 0.88rem; font-size: 0.88rem;
color: var(--subtext0); color: var(--subtext0);
max-width: 420px; max-width: 420px;
line-height: 1.8; line-height: 1.8;
margin-bottom: 2.5rem; margin-bottom: 2.5rem;
opacity: 0; opacity: 0;
animation: fadeUp 0.6s 0.5s forwards; animation: fadeUp 0.6s 0.5s forwards;
} }
.nf-terminal { .nf-terminal {
background: var(--mantle); background: var(--mantle);
border: 1px solid var(--surface0); border: 1px solid var(--surface0);
border-radius: 8px; border-radius: 8px;
padding: 1rem 1.5rem; padding: 1rem 1.5rem;
font-size: 0.78rem; font-size: 0.78rem;
color: var(--subtext1); color: var(--subtext1);
text-align: left; text-align: left;
max-width: 440px; max-width: 440px;
width: 100%; width: 100%;
margin-bottom: 2.5rem; margin-bottom: 2.5rem;
opacity: 0; opacity: 0;
animation: fadeUp 0.6s 0.6s forwards; animation: fadeUp 0.6s 0.6s forwards;
} }
.nf-terminal-bar { .nf-terminal-bar {
display: flex; display: flex;
gap: 0.5rem; gap: 0.5rem;
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
} }
.nf-dot { .nf-dot {
width: 10px; width: 10px;
height: 10px; height: 10px;
border-radius: 50%; border-radius: 50%;
} }
.nf-dot--red { .nf-dot--red {
background: var(--red); background: var(--red);
opacity: 0.7; opacity: 0.7;
} }
.nf-dot--yellow { .nf-dot--yellow {
background: var(--yellow); background: var(--yellow);
opacity: 0.7; opacity: 0.7;
} }
.nf-dot--green { .nf-dot--green {
background: var(--green); background: var(--green);
opacity: 0.7; opacity: 0.7;
} }
.nf-terminal-line { .nf-terminal-line {
display: flex; display: flex;
gap: 0.6rem; gap: 0.6rem;
line-height: 1.9; line-height: 1.9;
} }
.nf-prompt { .nf-prompt {
color: var(--green); color: var(--green);
} }
.nf-cmd { .nf-cmd {
color: var(--text); color: var(--text);
} }
.nf-err { .nf-err {
color: var(--red); color: var(--red);
} }
.nf-comment { .nf-comment {
color: var(--overlay1); color: var(--overlay1);
} }
.nf-cursor { .nf-cursor {
display: inline-block; display: inline-block;
width: 0.55em; width: 0.55em;
height: 1em; height: 1em;
background: var(--mauve); background: var(--mauve);
vertical-align: text-bottom; vertical-align: text-bottom;
animation: blink 1.1s step-end infinite; animation: blink 1.1s step-end infinite;
} }
@keyframes blink { @keyframes blink {
0%, 100% { 0%,
opacity: 1; 100% {
} opacity: 1;
50% { }
opacity: 0; 50% {
} opacity: 0;
}
} }
.nf-actions { .nf-actions {
display: flex; display: flex;
gap: 1.25rem; gap: 1.25rem;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
opacity: 0; opacity: 0;
animation: fadeUp 0.6s 0.7s forwards; animation: fadeUp 0.6s 0.7s forwards;
} }

121
404.html
View File

@@ -1,83 +1,86 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head>
<head> <meta charset="UTF-8" />
<meta charset="UTF-8"/> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>404 — Havox</title> <title>404 — Havox</title>
<meta name="description" content="Page not found."/> <meta name="description" content="Page not found." />
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link <link
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,400;0,700;1,400&family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,600;1,9..144,300&display=swap" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,400;0,700;1,400&family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,600;1,9..144,300&display=swap"
rel="stylesheet"> rel="stylesheet"
<link rel="stylesheet" href="style.css"/> />
<link rel="stylesheet" href="404.css"/> <link rel="stylesheet" href="style.css" />
</head> <link rel="stylesheet" href="404.css" />
</head>
<body> <body>
<!-- ─── Nav ─────────────────────────────────────────────────── -->
<!-- ─── Nav ─────────────────────────────────────────────────── --> <nav>
<nav> <a href="index.html" class="nav-logo">havox</a>
<a href="index.html" class="nav-logo">havox</a> <ul class="nav-links">
<ul class="nav-links">
<li><a href="index.html#about">about</a></li> <li><a href="index.html#about">about</a></li>
<li><a href="index.html#skills">skills</a></li> <li><a href="index.html#skills">skills</a></li>
<li><a href="index.html#projects">projects</a></li> <li><a href="index.html#projects">projects</a></li>
<li><a href="index.html#contact">contact</a></li> <li><a href="index.html#contact">contact</a></li>
</ul> </ul>
</nav> </nav>
<!-- ─── 404 ──────────────────────────────────────────────────── --> <!-- ─── 404 ──────────────────────────────────────────────────── -->
<main class="not-found"> <main class="not-found">
<div class="nf-code">404</div>
<div class="nf-code">404</div> <p class="nf-eyebrow">page not found</p>
<h1 class="nf-heading">This page <em>doesn't exist</em></h1>
<p class="nf-desc">
Either this URL was wrong, something got moved, or you've stumbled onto
a dead link I haven't cleaned up yet. Wouldn't be the first time.
</p>
<p class="nf-eyebrow">page not found</p> <div class="nf-terminal" aria-hidden="true">
<h1 class="nf-heading">This page <em>doesn't exist</em></h1>
<p class="nf-desc">
Either this URL was wrong, something got moved, or you've stumbled onto a
dead link I haven't cleaned up yet. Wouldn't be the first time.
</p>
<div class="nf-terminal" aria-hidden="true">
<div class="nf-terminal-bar"> <div class="nf-terminal-bar">
<span class="nf-dot nf-dot--red"></span> <span class="nf-dot nf-dot--red"></span>
<span class="nf-dot nf-dot--yellow"></span> <span class="nf-dot nf-dot--yellow"></span>
<span class="nf-dot nf-dot--green"></span> <span class="nf-dot nf-dot--green"></span>
</div> </div>
<div class="nf-terminal-line"> <div class="nf-terminal-line">
<span class="nf-prompt">~</span> <span class="nf-prompt">~</span>
<span class="nf-cmd">curl -I <span id="typed-path"></span></span> <span class="nf-cmd">curl -I <span id="typed-path"></span></span>
</div> </div>
<div class="nf-terminal-line" id="nf-response" style="opacity:0; transition: opacity 0.3s;"> <div
<span class="nf-err">HTTP/1.1 404 Not Found</span> class="nf-terminal-line"
id="nf-response"
style="opacity: 0; transition: opacity 0.3s"
>
<span class="nf-err">HTTP/1.1 404 Not Found</span>
</div> </div>
<div class="nf-terminal-line" id="nf-hint" style="opacity:0; transition: opacity 0.3s;"> <div
<span class="nf-comment"># maybe try going home?</span> class="nf-terminal-line"
id="nf-hint"
style="opacity: 0; transition: opacity 0.3s"
>
<span class="nf-comment"># maybe try going home?</span>
</div> </div>
<div class="nf-terminal-line"> <div class="nf-terminal-line">
<span class="nf-prompt">~</span> <span class="nf-prompt">~</span>
<span class="nf-cursor"></span> <span class="nf-cursor"></span>
</div> </div>
</div> </div>
<div class="nf-actions"> <div class="nf-actions">
<a href="/" class="btn btn-primary">← Back home</a> <a href="/" class="btn btn-primary">← Back home</a>
</div> </div>
</main>
</main> <!-- ─── Footer ─────────────────────────────────────────────────── -->
<footer>
<span>umbra.mom — John Gatward</span>
<span>
Source code (selfhosted):
<a href="https://gitea.umbra.mom/jay/havox">repository</a>
</span>
</footer>
<!-- ─── Footer ─────────────────────────────────────────────────── --> <script src="404.js"></script>
<footer> </body>
<span>umbra.mom — John Gatward</span>
<span>
Source code (selfhosted): <a href="https://gitea.umbra.mom/jay/havox">repository</a>
</span>
</footer>
<script src="404.js">
</script>
</body>
</html> </html>

1011
index.html

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,18 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head>
<head> <meta
<meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0> name="viewport"
width="device-width,"
initial-scale="1.0,"
maximum-scale="1.0,"
user-scalable="0"
/>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<script src="cPoint.js"></script> <script src="cPoint.js"></script>
<script src="cLine.js"></script> <script src="cLine.js"></script>
<script src="sketch.js"></script> <script src="sketch.js"></script>
</head> </head>
<body>
</body>
<body></body>
</html> </html>

View File

@@ -1,184 +1,191 @@
<DOCTYPE! html> <!doctype html>
<html> <html>
<head>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
</head>
<head> <style>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script> body {
</head> font-family: Arial, sans-serif;
background: #fafafa;
margin: 20px;
text-align: center;
}
<style> #container {
body { max-width: 900px;
font-family: Arial, sans-serif; margin: 0 auto;
background: #fafafa; }
margin: 20px;
text-align: center; h1,
h2,
p {
margin: 10px 0;
}
</style>
<div id="container">
<h1>Ellipse Construction</h1>
<p>
Inspired by a Richard Feyman's
<a href="https://en.wikipedia.org/wiki/Feynman's_Lost_Lecture"
>lost lecture</a
>
&
<a href="https://www.youtube.com/watch?v=xdIjYBtnvZU"
>3blue1brown's video</a
>.
</p>
<p>A geometric proof as to why planetary orbits are ellipitcal.</p>
<h2 id="PIbox"></h2>
<h3 id="percentage"></h3>
</div>
<script>
class dot {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
var ux, uy;
var points = [];
var numericValue = 15;
function setup() {
createCanvas(800, 800);
background(41);
}
function draw() {
translate(width / 2, height / 2);
background(41);
stroke(75, 75, 215);
strokeWeight(3);
noFill();
ellipse(0, 0, width - 0.0625 * width, height - 0.0625 * height);
stroke(215, 215, 15);
strokeWeight(7);
point(0, 0);
if (mouseY > 0 && mouseY < height && mouseX > 0 && mouseX < width) {
if (mouseIsPressed == true && mouseButton == LEFT) {
ux = mouseX - width / 2;
uy = mouseY - height / 2;
point(ux, uy);
getCirclePoints();
drawLines(ux, uy);
drawTLines(ux, uy);
} else if (mouseIsPressed == true && mouseButton == RIGHT) {
ux = mouseX - width / 2;
uy = mouseY - height / 2;
point(ux, uy);
getCirclePoints();
drawTLines(ux, uy);
} }
}
}
#container { function getCirclePoints() {
max-width: 900px; var r = (width - 0.0625 * width) / 2;
margin: 0 auto; var step = 1 / numericValue;
var index = 0;
for (var i = 0; i < TWO_PI; i += step) {
var cx = r * Math.sin(i);
var cy = r * Math.cos(i);
points[index] = new dot(cx, cy);
index++;
}
}
function drawLines(startX, startY) {
strokeWeight(0.4);
stroke(255, 100);
for (var i = 0; i < points.length; i++) {
line(startX, startY, points[i].x, points[i].y);
//findMidpoint(startX, startY, points[i].x, points[i].y);
}
}
function drawTLines(startX, startY) {
strokeWeight(0.4);
stroke(255);
for (var i = 0; i < points.length; i++) {
findMidpoint(startX, startY, points[i].x, points[i].y);
}
}
function findMidpoint(x1, y1, x2, y2) {
//find center
var cx = (x1 + x2) / 2;
var cy = (y1 + y2) / 2;
//move line to the center on the origin
x1 -= cx;
y1 -= cy;
x2 -= cx;
y2 -= cy;
//rotate both points
xtemp = x1;
ytemp = y1;
x1 = -ytemp;
y1 = xtemp;
xtemp = x2;
ytemp = y2;
x2 = -ytemp;
y2 = xtemp;
//move the center point back to where it was
x1 += cx;
y1 += cy;
x2 += cx;
y2 += cy;
stroke(255, 0, 0);
line(x1, y1, x2, y2);
stroke(255);
}
function genLines() {
var pointOk = false;
do {
ux = random(width);
uy = random(height);
if (getDist(0, ux, 0, uy) <= (width - 0.0625 * width) / 2) {
pointOk = true;
} }
} while (!pointOk);
h1, point(ux, uy);
h2, getCirclePoints();
p { drawLines(ux, uy);
margin: 10px 0; drawTLines(ux, uy);
}
function genTLines() {
var pointOk = false;
do {
ux = random(width);
uy = random(height);
if (getDist(0, ux, 0, uy) <= (width - 0.0625 * width) / 2) {
pointOk = true;
} }
</style> } while (!pointOk);
<div id="container"> point(ux, uy);
<h1>Ellipse Construction</h1> getCirclePoints();
drawTLines(ux, uy);
}
<p> function getDist(x1, x2, y1, y2) {
Inspired by a Richard Feyman's <a href="https://en.wikipedia.org/wiki/Feynman's_Lost_Lecture">lost return Math.sqrt((x1 - x2) ^ (2 + (y1 - y2)) ^ 2);
lecture</a> & <a href="https://www.youtube.com/watch?v=xdIjYBtnvZU">3blue1brown's video</a>. }
</p> </script>
<p>A geometric proof as to why planetary orbits are ellipitcal.</p> </html>
<h2 id="PIbox"></h2>
<h3 id="percentage"></h3>
</div>
<script>
class dot {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
var ux, uy;
var points = [];
var numericValue = 15;
function setup() {
createCanvas(800, 800);
background(41);
}
function draw() {
translate(width / 2, height / 2);
background(41);
stroke(75, 75, 215);
strokeWeight(3);
noFill();
ellipse(0, 0, width - (0.0625 * width), height - (0.0625 * height));
stroke(215, 215, 15);
strokeWeight(7);
point(0, 0);
if (mouseY > 0 && mouseY < height && mouseX > 0 && mouseX < width) {
if (mouseIsPressed == true && mouseButton == LEFT) {
ux = mouseX - width / 2;
uy = mouseY - height / 2;
point(ux, uy);
getCirclePoints();
drawLines(ux, uy);
drawTLines(ux, uy);
} else if (mouseIsPressed == true && mouseButton == RIGHT) {
ux = mouseX - width / 2;
uy = mouseY - height / 2;
point(ux, uy);
getCirclePoints();
drawTLines(ux, uy);
}
}
}
function getCirclePoints() {
var r = (width - (0.0625 * width)) / 2;
var step = 1 / numericValue;
var index = 0;
for (var i = 0; i < TWO_PI; i += step) {
var cx = r * Math.sin(i);
var cy = r * Math.cos(i);
points[index] = new dot(cx, cy);
index++;
}
}
function drawLines(startX, startY) {
strokeWeight(0.4);
stroke(255, 100);
for (var i = 0; i < points.length; i++) {
line(startX, startY, points[i].x, points[i].y);
//findMidpoint(startX, startY, points[i].x, points[i].y);
}
}
function drawTLines(startX, startY) {
strokeWeight(0.4);
stroke(255);
for (var i = 0; i < points.length; i++) {
findMidpoint(startX, startY, points[i].x, points[i].y);
}
}
function findMidpoint(x1, y1, x2, y2) {
//find center
var cx = (x1 + x2) / 2;
var cy = (y1 + y2) / 2;
//move line to the center on the origin
x1 -= cx; y1 -= cy;
x2 -= cx; y2 -= cy;
//rotate both points
xtemp = x1; ytemp = y1;
x1 = -ytemp; y1 = xtemp;
xtemp = x2; ytemp = y2;
x2 = -ytemp; y2 = xtemp;
//move the center point back to where it was
x1 += cx; y1 += cy;
x2 += cx; y2 += cy;
stroke(255, 0, 0);
line(x1, y1, x2, y2);
stroke(255);
}
function genLines() {
var pointOk = false;
do {
ux = random(width);
uy = random(height);
if (getDist(0, ux, 0, uy) <= (width - (0.0625 * width)) / 2) {
pointOk = true;
}
}
while (!pointOk);
point(ux, uy);
getCirclePoints();
drawLines(ux, uy);
drawTLines(ux, uy);
}
function genTLines() {
var pointOk = false;
do {
ux = random(width);
uy = random(height);
if (getDist(0, ux, 0, uy) <= (width - (0.0625 * width)) / 2) {
pointOk = true;
}
}
while (!pointOk);
point(ux, uy);
getCirclePoints();
drawTLines(ux, uy);
}
function getDist(x1, x2, y1, y2) {
return Math.sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2);
}
</script>
</html>

View File

@@ -1,78 +1,106 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Flocking Boids - WASM</title> <title>Flocking Boids - WASM</title>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css" />
</head> </head>
<body> <body>
<div id="container"> <div id="container">
<canvas id="canvas"></canvas> <canvas id="canvas"></canvas>
<aside id="controls" aria-expanded="true"> <aside id="controls" aria-expanded="true">
<div id="controlsHeader"> <div id="controlsHeader">
<h2 id="controlsTitle">Flocking Controls</h2> <h2 id="controlsTitle">Flocking Controls</h2>
<button id="controlsToggle" type="button" aria-controls="controlsBody" aria-expanded="true" aria-label="Collapse controls"></button> <button
id="controlsToggle"
type="button"
aria-controls="controlsBody"
aria-expanded="true"
aria-label="Collapse controls"
>
</button>
</div>
<div id="controlsBody">
<div class="control-group">
<label for="alignSlider">Alignment</label>
<input
type="range"
id="alignSlider"
min="0"
max="5"
step="0.1"
value="1.0"
/>
<div class="value-display">
<span class="stat-label">Weight:</span>
<strong id="alignValue">1.00</strong>
</div> </div>
<div id="controlsBody"> </div>
<div class="control-group">
<label for="alignSlider">Alignment</label>
<input type="range" id="alignSlider" min="0" max="5" step="0.1" value="1.0">
<div class="value-display">
<span class="stat-label">Weight:</span>
<strong id="alignValue">1.00</strong>
</div>
</div>
<div class="control-group"> <div class="control-group">
<label for="cohesionSlider">Cohesion</label> <label for="cohesionSlider">Cohesion</label>
<input type="range" id="cohesionSlider" min="0" max="5" step="0.1" value="0.9"> <input
<div class="value-display"> type="range"
<span class="stat-label">Weight:</span> id="cohesionSlider"
<strong id="cohesionValue">0.90</strong> min="0"
</div> max="5"
</div> step="0.1"
value="0.9"
<div class="control-group"> />
<label for="separationSlider">Separation</label> <div class="value-display">
<input type="range" id="separationSlider" min="0" max="5" step="0.1" value="1.4"> <span class="stat-label">Weight:</span>
<div class="value-display"> <strong id="cohesionValue">0.90</strong>
<span class="stat-label">Weight:</span>
<strong id="separationValue">1.40</strong>
</div>
</div>
<div class="divider"></div>
<div class="control-group">
<label for="addBtn">Boid Count (Step: 10)</label>
<div class="button-group">
<button id="removeBtn" type="button">10 Remove</button>
<button id="addBtn" type="button">+10 Add</button>
</div>
<div class="value-display">
<span class="stat-label">Total:</span>
<strong id="boidCount">250</strong>
</div>
</div>
<div class="divider"></div>
<div class="stats">
<div class="stat-item">
<span class="stat-label">Canvas:</span>
<span class="stat-value" id="canvasSize">0x0</span>
</div>
<div class="stat-item">
<span class="stat-label">FPS:</span>
<span class="stat-value" id="fps">60</span>
</div>
</div>
</div> </div>
</aside> </div>
<div class="control-group">
<label for="separationSlider">Separation</label>
<input
type="range"
id="separationSlider"
min="0"
max="5"
step="0.1"
value="1.4"
/>
<div class="value-display">
<span class="stat-label">Weight:</span>
<strong id="separationValue">1.40</strong>
</div>
</div>
<div class="divider"></div>
<div class="control-group">
<label for="addBtn">Boid Count (Step: 10)</label>
<div class="button-group">
<button id="removeBtn" type="button">10 Remove</button>
<button id="addBtn" type="button">+10 Add</button>
</div>
<div class="value-display">
<span class="stat-label">Total:</span>
<strong id="boidCount">250</strong>
</div>
</div>
<div class="divider"></div>
<div class="stats">
<div class="stat-item">
<span class="stat-label">Canvas:</span>
<span class="stat-value" id="canvasSize">0x0</span>
</div>
<div class="stat-item">
<span class="stat-label">FPS:</span>
<span class="stat-value" id="fps">60</span>
</div>
</div>
</div>
</aside>
</div> </div>
<script type="module" src="script.js"></script> <script type="module" src="script.js"></script>
</body> </body>
</html> </html>

View File

@@ -1,122 +1,120 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head>
<head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>Fourier Series — Epicycles (p5.js)</title> <title>Fourier Series — Epicycles (p5.js)</title>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<style> <style>
body { body {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
background: #fafafa; background: #fafafa;
margin: 20px; margin: 20px;
text-align: center; text-align: center;
} }
#container { #container {
max-width: 900px; max-width: 900px;
margin: 0 auto; margin: 0 auto;
} }
h1, h1,
h2, h2,
p { p {
margin: 10px 0; margin: 10px 0;
} }
input[type="range"] { input[type="range"] {
display: block; display: block;
margin: 10px auto 0; margin: 10px auto 0;
width: 260px; width: 260px;
} }
</style> </style>
</head> </head>
<body>
<body>
<div id="container"> <div id="container">
<h1>Fourier Series</h1> <h1>Fourier Series</h1>
<p> <p>
This interactive sketch visualizes a Fourier series using epicycles. Each circle represents This interactive sketch visualizes a Fourier series using epicycles.
an odd harmonic; as you add more epicycles with the slider, the path on the right converges toward a Each circle represents an odd harmonic; as you add more epicycles with
square wave. The rotating vectors sum to a point whose vertical position is traced over time. the slider, the path on the right converges toward a square wave. The
</p> rotating vectors sum to a point whose vertical position is traced over
time.
</p>
<div class="canvas-holder"> <div class="canvas-holder"></div>
</div>
</div> </div>
<script> <script>
class dot { class dot {
constructor(x, y) { constructor(x, y) {
this.x = x; this.x = x;
this.y = y; this.y = y;
}
} }
}
class circle { class circle {
constructor(cx, cy, r, a) { constructor(cx, cy, r, a) {
this.cx = cx; this.cx = cx;
this.cy = cy; this.cy = cy;
this.r = r; this.r = r;
this.a = a; this.a = a;
}
} }
}
let time = 0; let time = 0;
let wave = []; let wave = [];
let slider; let slider;
function setup() { function setup() {
createCanvas(900, 800); createCanvas(900, 800);
slider = createSlider(1, 50, 5); slider = createSlider(1, 50, 5);
}
function draw() {
background(41);
translate(250, height / 2);
let x = 0;
let y = 0;
for (let i = 0; i < slider.value(); i++) {
let prevx = x;
let prevy = y;
let n = i * 2 + 1;
let radius = 100 * (4 / (n * PI));
x += radius * cos(n * time);
y += radius * sin(n * time);
stroke(255, 100);
noFill();
ellipse(prevx, prevy, radius * 2);
//fill(255);
stroke(255);
line(prevx, prevy, x, y);
//ellipse(x, y, 8);
} }
wave.unshift(y);
function draw() { translate(200, 0);
background(41); line(x - 200, y, 0, wave[0]);
translate(250, height / 2); beginShape();
noFill();
let x = 0; for (let i = 0; i < wave.length; i++) {
let y = 0; vertex(i, wave[i]);
for (let i = 0; i < slider.value(); i++) {
let prevx = x;
let prevy = y;
let n = i * 2 + 1;
let radius = 100 * (4 / (n * PI));
x += radius * cos(n * time);
y += radius * sin(n * time);
stroke(255, 100);
noFill();
ellipse(prevx, prevy, radius * 2);
//fill(255);
stroke(255);
line(prevx, prevy, x, y);
//ellipse(x, y, 8);
}
wave.unshift(y);
translate(200, 0);
line(x - 200, y, 0, wave[0]);
beginShape();
noFill();
for (let i = 0; i < wave.length; i++) {
vertex(i, wave[i]);
}
endShape();
time += 0.02;
if (wave.length > 450) {
wave.pop();
}
} }
endShape();
time += 0.02;
if (wave.length > 450) {
wave.pop();
}
}
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,224 +1,247 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head>
<head> <meta
<meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0> name="viewport"
width="device-width,"
initial-scale="1.0,"
maximum-scale="1.0,"
user-scalable="0"
/>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<style> <style>
body { body {
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; font-family:
margin: 16px; system-ui,
background: #fafafa; -apple-system,
color: #222; Segoe UI,
} Roboto,
Helvetica,
Arial,
sans-serif;
margin: 16px;
background: #fafafa;
color: #222;
}
.intro { .intro {
max-width: 900px; max-width: 900px;
margin: 0 auto 18px; margin: 0 auto 18px;
padding: 0 12px; padding: 0 12px;
} }
.intro h1 { .intro h1 {
font-size: 1.5rem; font-size: 1.5rem;
margin: 0 0 6px; margin: 0 0 6px;
} }
.intro p { .intro p {
margin: 4px 0 10px; margin: 4px 0 10px;
line-height: 1.45; line-height: 1.45;
} }
canvas { canvas {
display: block; display: block;
margin: 0 auto; margin: 0 auto;
} }
</style> </style>
</head>
</head> <body>
<body>
<div class="intro"> <div class="intro">
<h1>Marching Squares Field Visualizer</h1> <h1>Marching Squares Field Visualizer</h1>
<p> <p>
This sketch uses the <strong>Marching Squares</strong> algorithm to generate and display contour boundaries This sketch uses the <strong>Marching Squares</strong> algorithm to
on a grid. Each cell is either active or inactive, the algorithm determines the correct line or triangle to generate and display contour boundaries on a grid. Each cell is either
draw based on the surrounding corners. active or inactive, the algorithm determines the correct line or
</p> triangle to draw based on the surrounding corners.
<p> </p>
<b>Left-click</b> toggles a cell between the two states. <p><b>Left-click</b> toggles a cell between the two states.</p>
</p> <p>
<p> <b>Rightclick</b> shows or hides the contour lines produced by the
<b>Rightclick</b> shows or hides the contour lines produced by the algorithm. algorithm.
</p> </p>
</div> </div>
<script> <script>
var reso = 50; var reso = 50;
var cols, rows; var cols, rows;
var field = []; var field = [];
var draw_lines = true; var draw_lines = true;
function setup() { function setup() {
createCanvas(800, 600); createCanvas(800, 600);
cols = width / reso + 1; cols = width / reso + 1;
rows = height / reso + 1; rows = height / reso + 1;
for (var i = 0; i < cols * rows; i++) for (var i = 0; i < cols * rows; i++) field[i] = Math.floor(random(2));
field[i] = Math.floor(random(2)); }
function draw() {
background(100);
const cBlue = color(55, 120, 232);
const cGreen = color(146, 232, 55);
for (var i = 0; i < cols * rows; i++) {
let x = i % cols;
let y = Math.floor(i / cols);
let c = field[i] ? cBlue : cGreen;
fill(c);
rect(x * reso - reso * 0.5, y * reso - reso * 0.5, reso, reso);
} }
function draw() { for (var i = 0; i < cols * rows; i++) {
background(100); if (i + cols + 1 > cols * rows) {
const cBlue = color(55, 120, 232); break;
const cGreen = color(146, 232, 55); }
for (var i = 0; i < cols * rows; i++) { var x = (i % cols) * reso;
let x = i % cols; var y = Math.floor(i / cols) * reso;
let y = Math.floor(i / cols);
let c = field[i] ? cBlue : cGreen; const a = [x + reso * 0.5, y];
fill(c); const b = [x + reso, y + reso * 0.5];
const c = [x + reso * 0.5, y + reso];
const d = [x, y + reso * 0.5];
rect(x * reso - reso * 0.5, y * reso - reso * 0.5, reso, reso); var s = getState(
} field[i],
field[i + 1],
field[i + cols + 1],
field[i + cols],
);
noStroke();
for (var i = 0; i < cols * rows; i++) { switch (s) {
if (i + cols + 1 > cols * rows) {break;} case 1:
fill(cGreen);
var x = (i % cols) * reso; triangle(x + reso * 0.5, y + reso * 0.5, c[0], c[1], d[0], d[1]);
var y = (Math.floor(i / cols)) * reso; break;
case 14:
const a = [x + reso * 0.5, y]; fill(cBlue);
const b = [x + reso, y + reso * 0.5]; triangle(x + reso * 0.5, y + reso * 0.5, c[0], c[1], d[0], d[1]);
const c = [x + reso * 0.5, y + reso]; break;
const d = [x, y + reso * 0.5]; case 2:
fill(cGreen);
var s = getState(field[i], field[i + 1], field[i + cols + 1], field[i + cols]); triangle(x + reso * 0.5, y + reso * 0.5, b[0], b[1], c[0], c[1]);
noStroke(); break;
case 13:
switch (s) { fill(cBlue);
case 1: triangle(x + reso * 0.5, y + reso * 0.5, b[0], b[1], c[0], c[1]);
fill(cGreen); break;
triangle(x + reso * 0.5, y + reso * 0.5, c[0], c[1], d[0], d[1]); case 3:
break; fill(cBlue);
case 14: rect(d[0], d[1], reso, reso * 0.5);
fill(cBlue); break;
triangle(x + reso * 0.5, y + reso * 0.5, c[0], c[1], d[0], d[1]); case 12:
break; fill(cGreen);
case 2: rect(d[0], d[1], reso, reso * 0.5);
fill(cGreen); break;
triangle(x + reso * 0.5, y + reso * 0.5, b[0], b[1], c[0], c[1]); case 4:
break; fill(cGreen);
case 13: triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], b[0], b[1]);
fill(cBlue); break;
triangle(x + reso * 0.5, y + reso * 0.5, b[0], b[1], c[0], c[1]); case 11:
break; fill(cBlue);
case 3: triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], b[0], b[1]);
fill(cBlue); break;
rect(d[0], d[1], reso, reso * 0.5); case 5:
break; fill(cBlue);
case 12: triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], d[0], d[1]);
fill(cGreen); triangle(x + reso * 0.5, y + reso * 0.5, b[0], b[1], c[0], c[1]);
rect(d[0], d[1], reso, reso * 0.5); break;
break; case 6:
case 4: fill(cBlue);
fill(cGreen); rect(a[0], a[1], reso * 0.5, reso);
triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], b[0], b[1]); break;
break; case 9:
case 11: fill(cGreen);
fill(cBlue); rect(a[0], a[1], reso * 0.5, reso);
triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], b[0], b[1]); break;
break; case 7:
case 5: fill(cBlue);
fill(cBlue); triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], d[0], d[1]);
triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], d[0], d[1]); break;
triangle(x + reso * 0.5, y + reso * 0.5, b[0], b[1], c[0], c[1]); case 8:
break; fill(cGreen);
case 6: triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], d[0], d[1]);
fill(cBlue); break;
rect(a[0], a[1], reso * 0.5, reso); case 10:
break; fill(cBlue);
case 9: triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], b[0], b[1]);
fill(cGreen); triangle(x + reso * 0.5, y + reso * 0.5, c[0], c[1], d[0], d[1]);
rect(a[0], a[1], reso * 0.5, reso); break;
break; default:
case 7: break;
fill(cBlue); }
triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], d[0], d[1]); if (draw_lines) {
break; drawLines(s, a, b, c, d);
case 8: }
fill(cGreen);
triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], d[0], d[1]);
break;
case 10:
fill(cBlue);
triangle(x + reso * 0.5, y + reso * 0.5, a[0], a[1], b[0], b[1]);
triangle(x + reso * 0.5, y + reso * 0.5, c[0], c[1], d[0], d[1]);
break;
default:
break;
};
if (draw_lines) {drawLines(s, a, b, c, d);}
}
} }
}
function getState(a, b, c, d) { function getState(a, b, c, d) {
return d * 1 + c * 2 + b * 4 + a * 8; return d * 1 + c * 2 + b * 4 + a * 8;
}
function drawLines(s, a, b, c, d) {
stroke(232, 229, 55);
strokeWeight(reso * 0.1);
switch (s) {
case 1:
case 14:
line(c[0], c[1], d[0], d[1]);
break;
case 2:
case 13:
line(b[0], b[1], c[0], c[1]);
break;
case 3:
case 12:
line(b[0], b[1], d[0], d[1]);
break;
case 4:
case 11:
line(a[0], a[1], b[0], b[1]);
break;
case 5:
line(a[0], a[1], d[0], d[1]);
line(b[0], b[1], c[0], c[1]);
break;
case 6:
case 9:
line(a[0], a[1], c[0], c[1]);
break;
case 7:
case 8:
line(a[0], a[1], d[0], d[1]);
break;
case 10:
line(a[0], a[1], b[0], b[1]);
line(c[0], c[1], d[0], d[1]);
break;
default:
break;
} }
noStroke();
}
function drawLines(s, a, b, c, d) { function mousePressed() {
stroke(232, 229, 55); if (mouseButton == LEFT) {
strokeWeight(reso * 0.1); var x = Math.floor((mouseX + 0.5 * reso) / reso);
switch (s) { var y = Math.floor((mouseY + 0.5 * reso) / reso);
case 1: case 14: var i = Math.floor(y * cols + x);
line(c[0], c[1], d[0], d[1]);
break; field[i] = (field[i] + 1) % 2;
case 2: case 13: } else if (mouseButton == RIGHT) {
line(b[0], b[1], c[0], c[1]); draw_lines = !draw_lines;
break;
case 3: case 12:
line(b[0], b[1], d[0], d[1]);
break;
case 4: case 11:
line(a[0], a[1], b[0], b[1]);
break;
case 5:
line(a[0], a[1], d[0], d[1]);
line(b[0], b[1], c[0], c[1]);
break;
case 6: case 9:
line(a[0], a[1], c[0], c[1]);
break;
case 7: case 8:
line(a[0], a[1], d[0], d[1]);
break;
case 10:
line(a[0], a[1], b[0], b[1]);
line(c[0], c[1], d[0], d[1]);
break;
default:
break;
};
noStroke();
}
function mousePressed() {
if (mouseButton == LEFT) {
var x = Math.floor((mouseX + 0.5 * reso) / reso);
var y = Math.floor((mouseY + 0.5 * reso) / reso);
var i = Math.floor(y * cols + x);
field[i] = (field[i] + 1) % 2;
} else if (mouseButton == RIGHT) {
draw_lines = !draw_lines;
}
} }
}
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,12 +1,17 @@
<html> <html>
<head>
<head> <meta
<meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0> name="viewport"
width="device-width,"
initial-scale="1.0,"
maximum-scale="1.0,"
user-scalable="0"
/>
<style> <style>
body { body {
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
</style> </style>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<script src="sketch.js"></script> <script src="sketch.js"></script>
@@ -14,39 +19,34 @@
<title>Maze Generator</title> <title>Maze Generator</title>
<style> <style>
body { body {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
background: #fafafa; background: #fafafa;
margin: 20px; margin: 20px;
text-align: center; text-align: center;
} }
#container { #container {
max-width: 900px; max-width: 900px;
margin: 0 auto; margin: 0 auto;
} }
h1, h1,
h2, h2,
p { p {
margin: 10px 0; margin: 10px 0;
} }
</style> </style>
</head> </head>
<div id="container">
<div id="container">
<h1>Maze Generator</h1> <h1>Maze Generator</h1>
<p> <p>Toy maze generator using DFS & recursice back tracking.</p>
Toy maze generator using DFS & recursice back tracking.
</p>
<h2 id="PIbox"></h2> <h2 id="PIbox"></h2>
<h3 id="percentage"></h3> <h3 id="percentage"></h3>
</div> </div>
<body>
</body>
<body></body>
</html> </html>

View File

@@ -1,73 +1,82 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Percolation</title> <title>Percolation</title>
<link rel="stylesheet" href="style.css"/> <link rel="stylesheet" href="style.css" />
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<a href="/#projects" class="back-button">← Back</a> <a href="/#projects" class="back-button">← Back</a>
<header> <header>
<h1>Percolation</h1> <h1>Percolation</h1>
<p class="subtitle">A simulation written in C &amp; Raylib.</p> <p class="subtitle">A simulation written in C &amp; Raylib.</p>
</header> </header>
<section> <section>
<p> <p>
<strong>Percolation</strong> is a simple model for connectivity on a grid. Each cell is either open or closed. <strong>Percolation</strong> is a simple model for connectivity on a
This simulation stops as soon as there is a path from the top of the grid to the bottom through the open cells. grid. Each cell is either open or closed. This simulation stops as
</p> soon as there is a path from the top of the grid to the bottom through
<div class="info-box"> the open cells.
<p> </p>
In this simulation, cells are randomly opened on a grid. Percolation occurs when there exists <div class="info-box">
a connected path of open cells from the top to the bottom of the grid. It is a neat way to visualise <p>
threshold behaviour: below a certain probability nothing connects, and above it large connected regions In this simulation, cells are randomly opened on a grid. Percolation
suddenly begin to appear. occurs when there exists a connected path of open cells from the top
</p> to the bottom of the grid. It is a neat way to visualise threshold
</div> behaviour: below a certain probability nothing connects, and above
</section> it large connected regions suddenly begin to appear.
</p>
</div>
</section>
<div class="canvas-container"> <div class="canvas-container">
<div class="canvas-toolbar"> <div class="canvas-toolbar">
<p>Canvas</p> <p>Canvas</p>
<button id="fullscreenButton" class="action-button" type="button">Fullscreen</button> <button id="fullscreenButton" class="action-button" type="button">
</div> Fullscreen
</button>
<div class="canvas-shell">
<canvas id="canvas" aria-label="Percolation simulation canvas" oncontextmenu="event.preventDefault()"></canvas>
</div>
<div id="status" class="status">Downloading...</div>
<progress id="progress" value="0" max="100" hidden></progress>
<details>
<summary>Show console output</summary>
<label class="visually-hidden" for="output">Console output</label>
<textarea id="output" rows="8" readonly></textarea>
</details>
</div> </div>
<section> <div class="canvas-shell">
<h3>Technical Details</h3> <canvas
<p> id="canvas"
The simulation uses a <strong>disjoint-set (Union-Find)</strong> style connectivity algorithm. As random cells open, aria-label="Percolation simulation canvas"
each open cell is union-ed with its open neighbours, and two virtual nodes represent the top and bottom edges oncontextmenu="event.preventDefault()"
of the grid. Percolation is detected the moment those two virtual nodes become connected. ></canvas>
</p> </div>
<p>
This makes each update fast and scalable even for larger grids.
</p>
</section>
<footer> <div id="status" class="status">Downloading...</div>
<p>Built with C, Raylib, and WebAssembly</p> <progress id="progress" value="0" max="100" hidden></progress>
</footer>
<details>
<summary>Show console output</summary>
<label class="visually-hidden" for="output">Console output</label>
<textarea id="output" rows="8" readonly></textarea>
</details>
</div>
<section>
<h3>Technical Details</h3>
<p>
The simulation uses a <strong>disjoint-set (Union-Find)</strong> style
connectivity algorithm. As random cells open, each open cell is
union-ed with its open neighbours, and two virtual nodes represent the
top and bottom edges of the grid. Percolation is detected the moment
those two virtual nodes become connected.
</p>
<p>This makes each update fast and scalable even for larger grids.</p>
</section>
<footer>
<p>Built with C, Raylib, and WebAssembly</p>
</footer>
</div> </div>
<script src="script.js"></script> <script src="script.js"></script>
<script async src="index.js"></script> <script async src="index.js"></script>
</body> </body>
</html> </html>

View File

@@ -1,197 +1,197 @@
* { * {
margin: 0; margin: 0;
padding: 0; padding: 0;
box-sizing: border-box; box-sizing: border-box;
} }
body { body {
background: white; background: white;
color: black; color: black;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
font-size: 16px; font-size: 16px;
line-height: 1.6; line-height: 1.6;
padding: 20px; padding: 20px;
} }
.container { .container {
max-width: 900px; max-width: 900px;
margin: 0 auto; margin: 0 auto;
} }
header { header {
text-align: center; text-align: center;
margin-bottom: 30px; margin-bottom: 30px;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
padding-bottom: 20px; padding-bottom: 20px;
} }
h1 { h1 {
font-size: 2.5rem; font-size: 2.5rem;
margin-bottom: 10px; margin-bottom: 10px;
} }
h2 { h2 {
font-size: 1.8rem; font-size: 1.8rem;
margin: 20px 0 15px; margin: 20px 0 15px;
} }
h3 { h3 {
font-size: 1.3rem; font-size: 1.3rem;
margin: 15px 0; margin: 15px 0;
} }
p { p {
margin-bottom: 15px; margin-bottom: 15px;
color: #333; color: #333;
} }
.subtitle { .subtitle {
color: #666; color: #666;
} }
.back-button { .back-button {
display: inline-block; display: inline-block;
margin-bottom: 20px; margin-bottom: 20px;
padding: 10px 15px; padding: 10px 15px;
background: #f0f0f0; background: #f0f0f0;
color: black; color: black;
text-decoration: none; text-decoration: none;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 4px; border-radius: 4px;
} }
.back-button:hover, .back-button:hover,
.action-button:hover { .action-button:hover {
background: #e0e0e0; background: #e0e0e0;
} }
.info-box { .info-box {
background: #f9f9f9; background: #f9f9f9;
border-left: 4px solid #333; border-left: 4px solid #333;
padding: 15px; padding: 15px;
margin: 20px 0; margin: 20px 0;
} }
.canvas-container { .canvas-container {
background: #f9f9f9; background: #f9f9f9;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 4px; border-radius: 4px;
padding: 20px; padding: 20px;
margin: 30px 0; margin: 30px 0;
} }
.canvas-toolbar { .canvas-toolbar {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
gap: 12px; gap: 12px;
margin-bottom: 15px; margin-bottom: 15px;
flex-wrap: wrap; flex-wrap: wrap;
} }
.canvas-toolbar p { .canvas-toolbar p {
margin: 0; margin: 0;
color: #666; color: #666;
font-size: 0.95rem; font-size: 0.95rem;
} }
.action-button { .action-button {
padding: 8px 12px; padding: 8px 12px;
background: #f0f0f0; background: #f0f0f0;
color: black; color: black;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
font: inherit; font: inherit;
} }
.canvas-shell { .canvas-shell {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
min-height: 500px; min-height: 500px;
overflow: auto; overflow: auto;
background: white; background: white;
border: 1px solid #ddd; border: 1px solid #ddd;
} }
#canvas { #canvas {
display: block; display: block;
margin: 0 auto; margin: 0 auto;
max-width: 100%; max-width: 100%;
height: auto; height: auto;
background: black; background: black;
outline: none; outline: none;
} }
.status { .status {
margin-top: 15px; margin-top: 15px;
min-height: 24px; min-height: 24px;
color: #666; color: #666;
} }
progress { progress {
width: 100%; width: 100%;
height: 16px; height: 16px;
margin-top: 10px; margin-top: 10px;
} }
progress[hidden] { progress[hidden] {
display: none; display: none;
} }
details { details {
margin-top: 15px; margin-top: 15px;
} }
.visually-hidden { .visually-hidden {
position: absolute; position: absolute;
width: 1px; width: 1px;
height: 1px; height: 1px;
padding: 0; padding: 0;
margin: -1px; margin: -1px;
overflow: hidden; overflow: hidden;
clip: rect(0, 0, 0, 0); clip: rect(0, 0, 0, 0);
white-space: nowrap; white-space: nowrap;
border: 0; border: 0;
} }
textarea { textarea {
width: 100%; width: 100%;
min-height: 120px; min-height: 120px;
margin-top: 10px; margin-top: 10px;
padding: 10px; padding: 10px;
border: 1px solid #ddd; border: 1px solid #ddd;
font-family: "Courier New", monospace; font-family: "Courier New", monospace;
font-size: 0.9rem; font-size: 0.9rem;
resize: vertical; resize: vertical;
background: white; background: white;
color: black; color: black;
} }
footer { footer {
text-align: center; text-align: center;
margin-top: 40px; margin-top: 40px;
padding-top: 20px; padding-top: 20px;
border-top: 1px solid #ccc; border-top: 1px solid #ccc;
font-size: 0.85rem; font-size: 0.85rem;
color: #666; color: #666;
} }
@media (max-width: 768px) { @media (max-width: 768px) {
body { body {
padding: 16px; padding: 16px;
} }
h1 { h1 {
font-size: 2rem; font-size: 2rem;
} }
.canvas-container { .canvas-container {
padding: 15px; padding: 15px;
} }
.canvas-shell { .canvas-shell {
min-height: 360px; min-height: 360px;
} }
} }

View File

@@ -1,48 +1,45 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<h1 id="PIbox"></h1>
<h2 id="percentage"></h2>
<h1 id="PIbox"></h1> <style>
<h2 id="percentage"></h2>
<style>
body { body {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
background: #fafafa; background: #fafafa;
margin: 20px; margin: 20px;
text-align: center; text-align: center;
} }
#container { #container {
max-width: 900px; max-width: 900px;
margin: 0 auto; margin: 0 auto;
} }
h1, h1,
h2, h2,
p { p {
margin: 10px 0; margin: 10px 0;
} }
</style> </style>
<div id="container">
<div id="container">
<h1>Monte Carlo π Estimator</h1> <h1>Monte Carlo π Estimator</h1>
<p> <p>
A small demonstation on how the Monte Carlo method can approximate the value of π A small demonstation on how the Monte Carlo method can approximate the
by randomly placing points inside a square and checking how many fall within value of π by randomly placing points inside a square and checking how
the inner circle. The closer the ratio gets to π/4, the more accurate many fall within the inner circle. The closer the ratio gets to π/4, the
the estimation becomes. more accurate the estimation becomes.
</p> </p>
<h2 id="PIbox"></h2> <h2 id="PIbox"></h2>
<h3 id="percentage"></h3> <h3 id="percentage"></h3>
</div> </div>
<script>
<script>
const r = 400; const r = 400;
var circleCount, total; var circleCount, total;
var x, y; var x, y;
@@ -52,53 +49,51 @@
var BestPI = 50; var BestPI = 50;
function setup() { function setup() {
createCanvas(r * 2, r * 2); createCanvas(r * 2, r * 2);
background(0); background(0);
stroke(255, 0, 0); stroke(255, 0, 0);
strokeWeight(3); strokeWeight(3);
noFill() noFill();
translate(width / 2, height / 2); translate(width / 2, height / 2);
rectMode(CENTER); rectMode(CENTER);
rect(0, 0, r * 2, r * 2); rect(0, 0, r * 2, r * 2);
ellipse(0, 0, r * 2, r * 2); ellipse(0, 0, r * 2, r * 2);
circleCount = 0; circleCount = 0;
total = 0; total = 0;
} }
function draw() { function draw() {
translate(width / 2, height / 2);
x = random(-r, r);
y = random(-r, r);
translate(width / 2, height / 2); stroke(0, 255, 0);
x = random(-r, r)
y = random(-r, r)
stroke(0, 255, 0) total += 1;
total += 1 var d = dist(x, y, 0, 0);
if (d < r) {
circleCount += 1;
stroke(0, 0, 255);
}
var d = dist(x, y, 0, 0) point(x, y);
if (d < r) {
circleCount += 1
stroke(0, 0, 255)
}
point(x, y); calcPI = 4 * (circleCount / total);
if (abs(PI - calcPI) < abs(PI - BestPI)) {
DisplayPI = calcPI;
BestPI = calcPI;
calcPI = 4 * (circleCount / total); var PIDisplay = document.getElementById("PIbox");
if (abs(PI - calcPI) < abs(PI - BestPI)) { PIDisplay.innerHTML = DisplayPI;
DisplayPI = calcPI;
BestPI = calcPI;
var PIDisplay = document.getElementById("PIbox"); var ErrorDisplay = document.getElementById("percentage");
PIDisplay.innerHTML = DisplayPI; var DisplayError = "a";
var Perror = (calcPI - PI) / PI;
var ErrorDisplay = document.getElementById("percentage"); Perror *= 100;
var DisplayError = "a"; DisplayError = nfc(Perror, 10);
var Perror = (calcPI - PI) / PI ErrorDisplay.innerHTML = DisplayError + "%";
Perror *= 100; }
DisplayError = nfc(Perror, 10);
ErrorDisplay.innerHTML = DisplayError + '%';
}
} }
</script> </script>
</html> </html>

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<script> <script>
var r = 10; //circle size var r = 10; //circle size
var k = 30; var k = 30;
var grid = []; var grid = [];
@@ -11,94 +11,93 @@
var ordered = []; var ordered = [];
function setup() { function setup() {
createCanvas(900, 900); createCanvas(900, 900);
background(0); background(0);
strokeWeight(4); strokeWeight(4);
colorMode(HSB); colorMode(HSB);
cols = floor(width / w);
rows = floor(height / w);
for (var i = 0; i < cols * rows; i++) {
grid[i] = undefined;
}
cols = floor(width / w); var x = width / 2;
rows = floor(height / w); var y = height / 2;
for (var i = 0; i < cols * rows; i++) { var i = floor(x / w);
grid[i] = undefined; var j = floor(y / w);
} var pos = createVector(x, y);
grid[i + j * cols] = pos;
active.push(pos);
var x = width / 2;
var y = height / 2;
var i = floor(x / w);
var j = floor(y / w);
var pos = createVector(x, y);
grid[i + j * cols] = pos;
active.push(pos);
} }
function draw() { function draw() {
background(0); background(0);
for (var total = 0; total < 30; total++) {
if (active.length > 0) {
var randIndex = floor(random(active.length));
var pos = active[randIndex];
var found = false;
for (var n = 0; n < k; n++) {
var sample = p5.Vector.random2D();
var m = random(r, 2 * r);
sample.setMag(m);
sample.add(pos);
for (var total = 0; total < 30; total++) { var col = floor(sample.x / w);
if (active.length > 0) { var row = floor(sample.y / w);
var randIndex = floor(random(active.length));
var pos = active[randIndex];
var found = false;
for (var n = 0; n < k; n++) {
var sample = p5.Vector.random2D();
var m = random(r, 2 * r);
sample.setMag(m);
sample.add(pos);
var col = floor(sample.x / w); if (
var row = floor(sample.y / w); col > -1 &&
row > -1 &&
if (col > -1 && row > -1 && col < cols && row < rows && !grid[col + row * cols]) { col < cols &&
var flag = true; row < rows &&
for (var i = -1; i <= 1; i++) { !grid[col + row * cols]
for (var j = -1; j <= 1; j++) { ) {
var index = (col + i) + (row + j) * cols; var flag = true;
var neighbor = grid[index]; for (var i = -1; i <= 1; i++) {
if (neighbor) { for (var j = -1; j <= 1; j++) {
var d = p5.Vector.dist(sample, neighbor); var index = col + i + (row + j) * cols;
if (d < r) { var neighbor = grid[index];
flag = false; if (neighbor) {
} var d = p5.Vector.dist(sample, neighbor);
} if (d < r) {
} flag = false;
}
if (flag) {
found = true;
grid[col + row * cols] = sample;
active.push(sample);
ordered.push(sample);
//break;
}
} }
}
} }
}
if (flag) {
found = true;
grid[col + row * cols] = sample;
active.push(sample);
ordered.push(sample);
if (!found) { //break;
active.splice(randIndex, 1); }
}
} }
} }
for (var i = 0; i < ordered.length; i++) { if (!found) {
active.splice(randIndex, 1);
stroke(255, 0, 255); }
strokeWeight(r * 0.5);
point(ordered[i].x, ordered[i].y);
} }
}
for (var i = 0; i < active.length; i++) { for (var i = 0; i < ordered.length; i++) {
if (ordered[i]) { stroke(255, 0, 255);
stroke(i % 360, 100, 100); strokeWeight(r * 0.5);
strokeWeight(r * 0.5); point(ordered[i].x, ordered[i].y);
point(active[i].x, active[i].y); }
}
for (var i = 0; i < active.length; i++) {
if (ordered[i]) {
stroke(i % 360, 100, 100);
strokeWeight(r * 0.5);
point(active[i].x, active[i].y);
} }
}
} }
</script> </script>
</html> </html>

View File

@@ -1,72 +1,91 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Thin Ice - a cute pixel art winter puzzle game." /> <meta
<title>Thin Ice | havox</title> name="description"
<link rel="stylesheet" href="style.css" /> content="Thin Ice - a cute pixel art winter puzzle game."
</head> />
<body> <title>Thin Ice | havox</title>
<div class="container"> <link rel="stylesheet" href="style.css" />
<a href="/#projects" class="back-button">← Back</a> </head>
<body>
<div class="container">
<a href="/#projects" class="back-button">← Back</a>
<header> <header>
<h1>Thin Ice</h1> <h1>Thin Ice</h1>
<p class="subtitle">Inspired by Club Penguin's Thin Ice mini-game.</p> <p class="subtitle">Inspired by Club Penguin's Thin Ice mini-game.</p>
</header> </header>
<section> <section>
<p>
You start on safe ice, breaking ice where you walk, trying to reach the finish tile before trapping yourself.
</p>
<div class="info-box">
<p> <p>
See if you can get a gold medal on all 6 levels by breaking every single tile of ice! You start on safe ice, breaking ice where you walk, trying to reach
the finish tile before trapping yourself.
</p> </p>
</div> <div class="info-box">
</section> <p>
See if you can get a gold medal on all 6 levels by breaking every
single tile of ice!
</p>
</div>
</section>
<div class="canvas-container"> <div class="canvas-container">
<div class="canvas-toolbar"> <div class="canvas-toolbar">
<p>Game</p> <p>Game</p>
<button id="fullscreenButton" class="action-button" type="button">Fullscreen</button> <button id="fullscreenButton" class="action-button" type="button">
Fullscreen
</button>
</div>
<div class="canvas-shell">
<canvas
id="canvas"
class="emscripten"
aria-label="Thin Ice game canvas"
oncontextmenu="event.preventDefault()"
tabindex="-1"
></canvas>
</div>
<div class="canvas-options">
<label
><input type="checkbox" id="resize" /> Resize canvas in
fullscreen</label
>
<label
><input type="checkbox" id="pointerLock" checked /> Lock pointer in
fullscreen</label
>
</div>
<div id="status" class="status">Downloading...</div>
<progress id="progress" value="0" max="100" hidden></progress>
<details>
<summary>Show console output</summary>
<label class="visually-hidden" for="output">Console output</label>
<textarea id="output" rows="8" readonly></textarea>
</details>
</div> </div>
<div class="canvas-shell"> <section>
<canvas id="canvas" class="emscripten" aria-label="Thin Ice game canvas" oncontextmenu="event.preventDefault()" tabindex="-1"></canvas> <h2>How to Play</h2>
</div> <ul class="feature-list">
<li>Use WASM keys to move across the ice.</li>
<li>Plan ahead so you do not strand yourself on broken tiles.</li>
<li>Reach the end tile without falling into the water.</li>
</ul>
</section>
<div class="canvas-options"> <footer>
<label><input type="checkbox" id="resize" /> Resize canvas in fullscreen</label> <p>Built with C++ & Raylib, compiled to WASM with emscripten.</p>
<label><input type="checkbox" id="pointerLock" checked /> Lock pointer in fullscreen</label> </footer>
</div>
<div id="status" class="status">Downloading...</div>
<progress id="progress" value="0" max="100" hidden></progress>
<details>
<summary>Show console output</summary>
<label class="visually-hidden" for="output">Console output</label>
<textarea id="output" rows="8" readonly></textarea>
</details>
</div> </div>
<section> <script src="script.js"></script>
<h2>How to Play</h2> <script async src="thin_ice.js"></script>
<ul class="feature-list"> </body>
<li>Use WASM keys to move across the ice.</li>
<li>Plan ahead so you do not strand yourself on broken tiles.</li>
<li>Reach the end tile without falling into the water.</li>
</ul>
</section>
<footer>
<p>Built with C++ & Raylib, compiled to WASM with emscripten.</p>
</footer>
</div>
<script src="script.js"></script>
<script async src="thin_ice.js"></script>
</body>
</html> </html>

View File

@@ -1,74 +1,107 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Travelling Salesman Problem</title> <title>Travelling Salesman Problem</title>
<link rel="stylesheet" href="./style.css" /> <link rel="stylesheet" href="./style.css" />
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<a href="/#projects" class="back-button">← Back</a> <a href="/#projects" class="back-button">← Back</a>
<header> <header>
<h1>Travelling Salesman Problem</h1> <h1>Travelling Salesman Problem</h1>
<p class="subtitle">An interactive route visualiser built with WebGL and WebAssembly.</p> <p class="subtitle">
</header> An interactive route visualiser built with WebGL and WebAssembly.
</p>
</header>
<section> <section>
<p> <p>
After writing one of my first tutorials on the Travelling Salesman Problem, I wanted to revisit it with a slightly more technical stack. After writing one of my first tutorials on the Travelling Salesman
The backend is written in Zig (compiled to WebAssembly), and the rendering is done directly in WebGL instead of p5.js or Raylib. Problem, I wanted to revisit it with a slightly more technical stack.
</p> 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> <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. Drag points around the canvas and watch the route update in real
time.
</p> </p>
</div>
</section>
<div class="info-box"> <div class="canvas-container">
<p> <div class="canvas-toolbar">
Drag points around the canvas and watch the route update in real time. <div class="control-group" aria-label="TSP controls">
</p> <label for="pointCountInput">Points</label>
</div> <input
</section> id="pointCountInput"
type="number"
<div class="canvas-container"> min="5"
<div class="canvas-toolbar"> max="100"
<div class="control-group" aria-label="TSP controls"> step="1"
<label for="pointCountInput">Points</label> value="36"
<input id="pointCountInput" type="number" min="5" max="100" step="1" value="36" /> />
<button id="applyPointCountButton" class="action-button" type="button">Regenerate</button> <button
</div> id="applyPointCountButton"
</div> class="action-button"
type="button"
<div class="canvas-shell"> >
<canvas id="tsp-canvas" aria-label="Travelling Salesman Problem canvas"> Regenerate
HTML5 canvas not supported in browser </button>
</canvas> </div>
</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> </div>
<section> <div class="canvas-shell">
<h3>Technical Details</h3> <canvas
<p> id="tsp-canvas"
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. aria-label="Travelling Salesman Problem canvas"
</p> >
<p> HTML5 canvas not supported in browser
Point coordinates are stored in WebAssembly memory, and the route order is recalculated whenever the layout changes. </canvas>
Rendering is handled in WebGL to keep interaction smooth as the point count increases. </div>
</p>
</section>
<footer> <div class="status-row">
<p>Built with Zig, WebGL2 and WebAssembly</p> <div id="pointCountStatus" class="status">36 points</div>
</footer> <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> </div>
<script src="./point.js"></script> <script src="./point.js"></script>
<script type="module" src="./main.js"></script> <script type="module" src="./main.js"></script>
</body> </body>
</html> </html>

View File

@@ -199,4 +199,3 @@ footer {
height: 400px; height: 400px;
} }
} }

View File

@@ -1,166 +1,222 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head>
<head> <meta
<meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0> name="viewport"
width="device-width,"
initial-scale="1.0,"
maximum-scale="1.0,"
user-scalable="0"
/>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<style> <style>
body { body {
padding: 0; padding: 0;
margin: 0; margin: 0;
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; font-family:
background: #fafafa; system-ui,
} -apple-system,
Segoe UI,
Roboto,
Helvetica,
Arial,
sans-serif;
background: #fafafa;
}
.intro { .intro {
max-width: 900px; max-width: 900px;
margin: 20px auto 10px; margin: 20px auto 10px;
padding: 0 16px; padding: 0 16px;
} }
.intro h1 { .intro h1 {
margin: 0 0 6px; margin: 0 0 6px;
font-size: 1.5rem; font-size: 1.5rem;
} }
.intro p { .intro p {
margin: 4px 0 14px; margin: 4px 0 14px;
line-height: 1.45; line-height: 1.45;
} }
.slidecontainer { .slidecontainer {
width: 100%; width: 100%;
/* Width of the outside container */ /* Width of the outside container */
} }
/* The slider itself */ /* The slider itself */
.slider { .slider {
-webkit-appearance: none; -webkit-appearance: none;
/* Override default CSS styles */ /* Override default CSS styles */
appearance: none; appearance: none;
width: 100%; width: 100%;
/* Full-width */ /* Full-width */
height: 25px; height: 25px;
/* Specified height */ /* Specified height */
background: #d3d3d3; background: #d3d3d3;
/* Grey background */ /* Grey background */
outline: none; outline: none;
/* Remove outline */ /* Remove outline */
opacity: 1; opacity: 1;
/* Set transparency (for mouse-over effects on hover) */ /* Set transparency (for mouse-over effects on hover) */
-webkit-transition: .2s; -webkit-transition: 0.2s;
/* 0.2 seconds transition on hover */ /* 0.2 seconds transition on hover */
transition: opacity .2s; transition: opacity 0.2s;
} }
.slider::-webkit-slider-thumb { .slider::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
/* Override default look */ /* Override default look */
appearance: none; appearance: none;
width: 25px; width: 25px;
/* Set a specific slider handle width */ /* Set a specific slider handle width */
height: 25px; height: 25px;
/* Slider handle height */ /* Slider handle height */
background: #434343; background: #434343;
/* Grey background */ /* Grey background */
cursor: pointer; cursor: pointer;
/* Cursor on hover */ /* Cursor on hover */
} }
.slider::-moz-range-thumb { .slider::-moz-range-thumb {
width: 25px; width: 25px;
/* Set a specific slider handle width */ /* Set a specific slider handle width */
height: 25px; height: 25px;
/* Slider handle height */ /* Slider handle height */
background: #434343; background: #434343;
/* Grey background */ /* Grey background */
cursor: pointer; cursor: pointer;
/* Cursor on hover */ /* Cursor on hover */
} }
</style> </style>
</head> </head>
<body>
<body>
<div class="intro"> <div class="intro">
<h1>Oscillating Arrow Field Visualizer</h1> <h1>Oscillating Arrow Field Visualizer</h1>
<p> <p>
A sketch to <s>hopefully</s> demonstrate the illusion of the <a A sketch to <s>hopefully</s> demonstrate the illusion of the
href="https://en.wikipedia.org/wiki/M%C3%BCller-Lyer_illusion">Müller-Lyer Illusion</a> <a href="https://en.wikipedia.org/wiki/M%C3%BCller-Lyer_illusion"
</p> >Müller-Lyer Illusion</a
<p>The lines - that are the same length, should look longer and shorter based on the angle of the arrow heads. >
</p> </p>
<p> <p>
Increasing the value adds more horizontal slices, creating a denser and more detailed pattern. The lines - that are the same length, should look longer and shorter
Tap or click to pause and resume the motion. based on the angle of the arrow heads.
</p> </p>
<p>
Increasing the value adds more horizontal slices, creating a denser and
more detailed pattern. Tap or click to pause and resume the motion.
</p>
</div> </div>
<div class="slidecontainer"> <div class="slidecontainer">
<input type="range" min="2" max="11" step="1" value="2" class="slider" id="myRange"> <input
type="range"
min="2"
max="11"
step="1"
value="2"
class="slider"
id="myRange"
/>
</div> </div>
<script> <script>
let vMargin, hMargin, arrowHeight, t, lineNum; let vMargin, hMargin, arrowHeight, t, lineNum;
let lineMove = true; let lineMove = true;
function setup() { function setup() {
createCanvas(windowWidth, windowHeight * 0.6); createCanvas(windowWidth, windowHeight * 0.6);
hMargin = 12; hMargin = 12;
arrowHeight = 25; arrowHeight = 25;
t = 0; t = 0;
lineNum = 1; lineNum = 1;
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight * 0.6);
}
function draw() {
background(43);
angleMode(DEGREES);
lineNum = document.getElementById("myRange").value;
drawLine(hMargin, lineNum + 1);
if (lineMove) {
t++;
} }
function windowResized() { if (t == 360) {
resizeCanvas(windowWidth, windowHeight * 0.6); t = 0;
} }
}
function draw() { function drawLine(hm, vm) {
background(43); //let changex = map(sin(t), -1, 1, -22, 22);
angleMode(DEGREES); let changex = sin(t) * 18;
lineNum = document.getElementById('myRange').value; vm /= 10;
for (let j = 1; j < vm - 1; j++) {
stroke(255, 34, 63);
strokeWeight(4);
line(width / hm, (j * height) / vm, width / 2, (j * height) / vm); //red line
drawLine(hMargin, lineNum + 1); stroke(69, 98, 255);
line(
width / 2,
(j * height) / vm,
((hm - 1) * width) / hm,
(j * height) / vm,
); //blue line
if (lineMove) { stroke(255);
t++; line(
} width / hm,
(j * height) / vm,
width / hm + changex,
(j * height) / vm - arrowHeight,
); //left top
line(
width / hm + changex,
(j * height) / vm + arrowHeight,
width / hm,
(j * height) / vm,
); //left bottom
if (t == 360) { line(
t = 0; ((hm - 1) * width) / hm + changex,
} (j * height) / vm + arrowHeight,
((hm - 1) * width) / hm,
(j * height) / vm,
); //right bottom
line(
width / 2 - changex,
(j * height) / vm + arrowHeight,
width / 2,
(j * height) / vm,
); //center bottom
line(
((hm - 1) * width) / hm,
(j * height) / vm,
((hm - 1) * width) / hm + changex,
(j * height) / vm - arrowHeight,
); //right bottom
line(
width / 2,
(j * height) / vm,
width / 2 - changex,
(j * height) / vm - arrowHeight,
); //center top
} }
}
function drawLine(hm, vm) { function mouseClicked() {
//let changex = map(sin(t), -1, 1, -22, 22); lineMove = !lineMove;
let changex = sin(t) * 18; }
vm /= 10;
for (let j = 1; j < vm - 1; j++) {
stroke(255, 34, 63);
strokeWeight(4);
line(width / hm, j * height / vm, width / 2, j * height / vm); //red line
stroke(69, 98, 255);
line(width / 2, j * height / vm, (hm - 1) * width / hm, j * height / vm); //blue line
stroke(255);
line(width / hm, j * height / vm, width / hm + changex, (j * height / vm) - arrowHeight); //left top
line(width / hm + changex, (j * height / vm) + arrowHeight, width / hm, j * height / vm); //left bottom
line((hm - 1) * width / hm + changex, j * height / vm + arrowHeight, (hm - 1) * width / hm, j * height / vm); //right bottom
line(width / 2 - changex, j * height / vm + arrowHeight, width / 2, j * height / vm); //center bottom
line((hm - 1) * width / hm, j * height / vm, (hm - 1) * width / hm + changex, (j * height / vm) - arrowHeight); //right bottom
line(width / 2, j * height / vm, width / 2 - changex, (j * height / vm) - arrowHeight); //center top
}
}
function mouseClicked() {
lineMove = !lineMove;
}
</script> </script>
</body> </body>
</html> </html>

1314
style.css

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
<DOCTYPE! html> <!DOCTYPE html>
<html> <html>
<title>Convex Hull</title> <title>Convex Hull</title>

View File

@@ -1,56 +1,55 @@
h1{ h1 {
font-family: 'Roboto Condensed', sans-serif; font-family: "Roboto Condensed", sans-serif;
margin: 0; margin: 0;
padding: 0 0 15px 0; padding: 0 0 15px 0;
font-weight: 700; font-weight: 700;
font-size: 32px; font-size: 32px;
} }
h2{ h2 {
font-family: 'Roboto Condensed', sans-serif; font-family: "Roboto Condensed", sans-serif;
margin: 0; margin: 0;
padding: 15px 0 15px 0; padding: 15px 0 15px 0;
font-weight: 650; font-weight: 650;
font-size: 20px; font-size: 20px;
} }
p{ p {
margin: 1px; margin: 1px;
font-family: 'Roboto', sans-serif; font-family: "Roboto", sans-serif;
font-size: 19px; font-size: 19px;
padding: 5px 0px 5px 0px; padding: 5px 0px 5px 0px;
} }
.psudoCode{ .psudoCode {
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
font-size: 19px; font-size: 19px;
background-color: #D9D9D9; background-color: #d9d9d9;
border: 1px solid; border: 1px solid;
padding: 5px; padding: 5px;
box-shadow: 5px 5px #888888; box-shadow: 5px 5px #888888;
} }
a{ a {
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
font-size: 19px; font-size: 19px;
background-color: #D9D9D9; background-color: #d9d9d9;
} }
button{ button {
background-color: white; background-color: white;
border: 2px solid #555555; border: 2px solid #555555;
color: black; color: black;
padding: 16px 32px; padding: 16px 32px;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
font-size: 16px; font-size: 16px;
margin: 4px 2px; margin: 4px 2px;
-webkit-transition-duration: 0.4s; /* Safari */ -webkit-transition-duration: 0.4s; /* Safari */
transition-duration: 0.4s; transition-duration: 0.4s;
cursor: pointer; cursor: pointer;
float:right; float: right;
} }
button:hover { button:hover {
@@ -58,14 +57,13 @@ button:hover {
color: white; color: white;
} }
.examples{ .examples {
padding: 10px; padding: 10px;
} }
html {
html{ -webkit-user-select: none; /* Safari */
-webkit-user-select: none; /* Safari */ -moz-user-select: none; /* Firefox */
-moz-user-select: none; /* Firefox */ -ms-user-select: none; /* IE10+/Edge */
-ms-user-select: none; /* IE10+/Edge */ user-select: none; /* Standard */
user-select: none; /* Standard */
} }

View File

@@ -1,56 +1,55 @@
h1{ h1 {
font-family: 'Roboto Condensed', sans-serif; font-family: "Roboto Condensed", sans-serif;
margin: 0; margin: 0;
padding: 0 0 15px 0; padding: 0 0 15px 0;
font-weight: 700; font-weight: 700;
font-size: 32px; font-size: 32px;
} }
h2{ h2 {
font-family: 'Roboto Condensed', sans-serif; font-family: "Roboto Condensed", sans-serif;
margin: 0; margin: 0;
padding: 15px 0 15px 0; padding: 15px 0 15px 0;
font-weight: 650; font-weight: 650;
font-size: 20px; font-size: 20px;
} }
p{ p {
margin: 1px; margin: 1px;
font-family: 'Roboto', sans-serif; font-family: "Roboto", sans-serif;
font-size: 19px; font-size: 19px;
padding: 5px 0px 5px 0px; padding: 5px 0px 5px 0px;
} }
.psudoCode{ .psudoCode {
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
font-size: 19px; font-size: 19px;
background-color: #D9D9D9; background-color: #d9d9d9;
border: 1px solid; border: 1px solid;
padding: 5px; padding: 5px;
box-shadow: 5px 5px #888888; box-shadow: 5px 5px #888888;
} }
a{ a {
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
font-size: 19px; font-size: 19px;
background-color: #D9D9D9; background-color: #d9d9d9;
} }
button{ button {
background-color: white; background-color: white;
border: 2px solid #555555; border: 2px solid #555555;
color: black; color: black;
padding: 16px 32px; padding: 16px 32px;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
font-size: 16px; font-size: 16px;
margin: 4px 2px; margin: 4px 2px;
-webkit-transition-duration: 0.4s; /* Safari */ -webkit-transition-duration: 0.4s; /* Safari */
transition-duration: 0.4s; transition-duration: 0.4s;
cursor: pointer; cursor: pointer;
float:right; float: right;
} }
button:hover { button:hover {
@@ -58,14 +57,13 @@ button:hover {
color: white; color: white;
} }
.examples{ .examples {
padding: 10px; padding: 10px;
} }
html {
html{ -webkit-user-select: none; /* Safari */
-webkit-user-select: none; /* Safari */ -moz-user-select: none; /* Firefox */
-moz-user-select: none; /* Firefox */ -ms-user-select: none; /* IE10+/Edge */
-ms-user-select: none; /* IE10+/Edge */ user-select: none; /* Standard */
user-select: none; /* Standard */
} }

View File

@@ -1,43 +1,49 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<link rel="stylesheet" <link
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/atom-one-dark.min.css" /> rel="stylesheet"
<link rel="stylesheet" href="style.css" /> href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/atom-one-dark.min.css"
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.2.0/p5.min.js" />
<link rel="stylesheet" href="style.css" />
<script
src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.2.0/p5.min.js"
integrity="sha512-b/htz6gIyFi3dwSoZ0Uv3cuv3Ony7EeKkacgrcVg8CMzu90n777qveu0PBcbZUA7TzyENGtU+qZRuFAkfqgyoQ==" integrity="sha512-b/htz6gIyFi3dwSoZ0Uv3cuv3Ony7EeKkacgrcVg8CMzu90n777qveu0PBcbZUA7TzyENGtU+qZRuFAkfqgyoQ=="
crossorigin="anonymous"></script> crossorigin="anonymous"
<script src="script.js"></script> ></script>
<script> <script src="script.js"></script>
<script>
fetch("snippets/defineCount.js") fetch("snippets/defineCount.js")
.then(r => r.text()) .then((r) => r.text())
.then(code => { .then((code) => {
document.getElementById("define-count").textContent = code; document.getElementById("define-count").textContent = code;
if (window.hljs) hljs.highlightElement(document.getElementById("define-count")); if (window.hljs)
}); hljs.highlightElement(document.getElementById("define-count"));
});
fetch("snippets/countSquares.js") fetch("snippets/countSquares.js")
.then(r => r.text()) .then((r) => r.text())
.then(code => { .then((code) => {
document.getElementById("count-squares").textContent = code; document.getElementById("count-squares").textContent = code;
if (window.hljs) hljs.highlightElement(document.getElementById("count-squares")); if (window.hljs)
}); hljs.highlightElement(document.getElementById("count-squares"));
</script> });
</script>
<head> <head>
<h1>Summed-area Table</h1> <h1>Summed-area Table</h1>
<p> <p>
A Summed-area table is a data structure and algorithm for quickly and A Summed-area table is a data structure and algorithm for quickly and
efficiently generating the sum of values in a rectangular grid. In image efficiently generating the sum of values in a rectangular grid. In image
processing it is also known as an integral image. processing it is also known as an integral image.
</p> </p>
</head> </head>
<body> <body>
<p> <p>
To generate a summed-area table, each cell is given a value which is the To generate a summed-area table, each cell is given a value which is the
sum of all values in a rectangular subset where the top left corner is the sum of all values in a rectangular subset where the top left corner is the
first cell in the grid and where the bottom right cell is the cell you're first cell in the grid and where the bottom right cell is the cell you're
calculating the value for (assumuing the array starts top left). calculating the value for (assumuing the array starts top left).
</p> </p>
<pre> <pre>
<code id="define-count" class="js"> <code id="define-count" class="js">
@@ -45,10 +51,10 @@
</pre> </pre>
<p> <p>
Now each cell has its own count value. This isn't much help on it's own, Now each cell has its own count value. This isn't much help on it's own,
however we can use it to calculate the sum value of any subset of the grid however we can use it to calculate the sum value of any subset of the grid
by interrogating 4 cells and performing only 4 additions. NOTE: we have to by interrogating 4 cells and performing only 4 additions. NOTE: we have to
add the 'top left' region as it as been subtracted twice. add the 'top left' region as it as been subtracted twice.
</p> </p>
<pre> <pre>
@@ -59,28 +65,26 @@
<p><b>Click</b> a sqaure on the grid to turn it on or off.</p> <p><b>Click</b> a sqaure on the grid to turn it on or off.</p>
<p><b>Shift+Click</b> two square to define a rectangle.</p> <p><b>Shift+Click</b> two square to define a rectangle.</p>
<p> <p>
Press the <b>show count</b> button to display the sum value of each cell Press the <b>show count</b> button to display the sum value of each cell
(in this example a cell's value can only be 0 or 1). (in this example a cell's value can only be 0 or 1).
</p> </p>
<p> <p>
Press <b>show rectangles</b> to see the different regions simplified and Press <b>show rectangles</b> to see the different regions simplified and
see how see how it changes the sum below.
it changes the sum below.
</p> </p>
<div id="sumDiv"> <div id="sumDiv">
<a id="subsetOutput">0</a> <a id="subsetOutput">0</a>
<a> = </a> <a> = </a>
<a id="wholeOutput"> 0</a> <a id="wholeOutput"> 0</a>
<a> + </a> <a> + </a>
<a id="tlOutput"> 0</a> <a id="tlOutput"> 0</a>
<a> - </a> <a> - </a>
<a id="lOutput"> 0</a> <a id="lOutput"> 0</a>
<a> - </a> <a> - </a>
<a id="tOutput"> 0</a> <a id="tOutput"> 0</a>
</div> </div>
<button onclick="showCountToggle()">Show count</button> <button onclick="showCountToggle()">Show count</button>
<button onclick="toggleRectMode()">Show rectangles</button> <button onclick="toggleRectMode()">Show rectangles</button>
</body> </body>
</html> </html>

View File

@@ -1,43 +1,54 @@
@import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap");
html { html {
background-color: #2e3440; } background-color: #2e3440;
}
h1 { h1 {
color: #eceff4; color: #eceff4;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
font-size: 48pt; } font-size: 48pt;
}
p { p {
color: #d8dee9; color: #d8dee9;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
font-size: 16pt; } font-size: 16pt;
}
code { code {
font-size: 14pt; font-size: 14pt;
border: 4px solid #ebcb8b; } border: 4px solid #ebcb8b;
}
a { a {
color: #d8dee9; color: #d8dee9;
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
font-size: 24pt; } font-size: 24pt;
}
#subsetOutput { #subsetOutput {
color: #88c0d0; } color: #88c0d0;
}
#wholeOutput { #wholeOutput {
color: #b48ead; } color: #b48ead;
}
#tlOutput { #tlOutput {
color: #d08770; } color: #d08770;
}
#tOutput { #tOutput {
color: #ebcb8b; } color: #ebcb8b;
}
#lOutput { #lOutput {
color: #a3be8c; } color: #a3be8c;
}
#sumDiv { #sumDiv {
text-align: center; } text-align: center;
}
button { button {
display: inline-block; display: inline-block;
@@ -47,22 +58,26 @@ button {
border: 4px solid #88c0d0; border: 4px solid #88c0d0;
box-sizing: border-box; box-sizing: border-box;
text-decoration: none; text-decoration: none;
font-family: 'Roboto',sans-serif; font-family: "Roboto", sans-serif;
font-size: 14pt; font-size: 14pt;
color: #434c5e; color: #434c5e;
background-color: #eceff4; background-color: #eceff4;
text-align: center; text-align: center;
position: relative; position: relative;
transition: all 0.15s; } transition: all 0.15s;
button:hover { }
background-color: #4c566a; button:hover {
color: #eceff4; background-color: #4c566a;
border-color: #5e81ac; } color: #eceff4;
button:focus { border-color: #5e81ac;
border: 4px solid #88c0d0; }
box-sizing: border-box; } button:focus {
border: 4px solid #88c0d0;
box-sizing: border-box;
}
#chillin { #chillin {
display: none; } display: none;
}
/*# sourceMappingURL=style.css.map */ /*# sourceMappingURL=style.css.map */

View File

@@ -1,79 +1,116 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<link href="style.css" rel="stylesheet" type="text/css"> <link href="style.css" rel="stylesheet" type="text/css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.2.0/p5.min.js" <script
src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.2.0/p5.min.js"
integrity="sha512-b/htz6gIyFi3dwSoZ0Uv3cuv3Ony7EeKkacgrcVg8CMzu90n777qveu0PBcbZUA7TzyENGtU+qZRuFAkfqgyoQ==" integrity="sha512-b/htz6gIyFi3dwSoZ0Uv3cuv3Ony7EeKkacgrcVg8CMzu90n777qveu0PBcbZUA7TzyENGtU+qZRuFAkfqgyoQ=="
crossorigin="anonymous"></script> crossorigin="anonymous"
></script>
<title>Travelling Sales Person</title> <title>Travelling Sales Person</title>
<h1>Travelling Sales Person Problem</h1> <h1>Travelling Sales Person Problem</h1>
<button id="backButton" onclick="window.location.href='/#tutorials'">Back</button> <button id="backButton" onclick="window.location.href = '/#tutorials'">
Back
</button>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<div class="pictureContainer"> <div class="pictureContainer">
<img src="https://optimization.mccormick.northwestern.edu/images/e/ea/48StatesTSP.png" alt="TSP Problem" <img
id="Conway"> src="https://optimization.mccormick.northwestern.edu/images/e/ea/48StatesTSP.png"
alt="TSP Problem"
id="Conway"
/>
</div> </div>
<p>The travelling salesman problem (TSP) asks the following question: "Given a list of cities and the distances <p>
between each pair of cities, what is the shortest possible route that visits each city and returns to the origin The travelling salesman problem (TSP) asks the following question: "Given
city?" </p> a list of cities and the distances between each pair of cities, what is
<p>The problem was first formulated in 1930 and is one of the most intensively studied problems in optimization. It the shortest possible route that visits each city and returns to the
is used as a benchmark for many optimization methods. Even though the problem is computationally difficult, a origin city?"
large number of heuristics and exact algorithms are known, so that some instances with tens of thousands of </p>
cities can be solved completely and even problems with millions of cities can be approximated within a small <p>
fraction of 1%.</p> The problem was first formulated in 1930 and is one of the most
<p>The TSP has several applications even in its purest formulation, such as planning, logistics, and the manufacture intensively studied problems in optimization. It is used as a benchmark
of microchips. Slightly modified, it appears as a sub-problem in many areas, such as DNA sequencing. In these for many optimization methods. Even though the problem is computationally
applications, the concept city represents, for example, customers, soldering points, or DNA fragments, and the difficult, a large number of heuristics and exact algorithms are known, so
concept distance represents travelling times or cost, or a similarity measure between DNA fragments. The TSP that some instances with tens of thousands of cities can be solved
also appears in astronomy, as astronomers observing many sources will want to minimize the time spent moving the completely and even problems with millions of cities can be approximated
telescope between the sources. In many applications, additional constraints such as limited resources or time within a small fraction of 1%.
windows may be imposed.</p> </p>
<p>
The TSP has several applications even in its purest formulation, such as
planning, logistics, and the manufacture of microchips. Slightly modified,
it appears as a sub-problem in many areas, such as DNA sequencing. In
these applications, the concept city represents, for example, customers,
soldering points, or DNA fragments, and the concept distance represents
travelling times or cost, or a similarity measure between DNA fragments.
The TSP also appears in astronomy, as astronomers observing many sources
will want to minimize the time spent moving the telescope between the
sources. In many applications, additional constraints such as limited
resources or time windows may be imposed.
</p>
<h2>These are some of the algorithms I used</h2> <h2>These are some of the algorithms I used</h2>
<p>Note the purple route is the best route it's found so far and the thin white lines are the routes it's trying <p>
real time.</p> Note the purple route is the best route it's found so far and the thin
</head> white lines are the routes it's trying real time.
</p>
</head>
<body> <body>
<div class="canvasBody"> <div class="canvasBody">
<h3>Random Sort</h3> <h3>Random Sort</h3>
<span id="c1"></span> <span id="c1"></span>
<p class="canvasText">This canvas sorts through random possiblities. Every frame the program chooses two random <p class="canvasText">
points (cities) and swaps them around. eg say the order was London, Paris, Madrid, the program would swap This canvas sorts through random possiblities. Every frame the program
London and Paris so that the new order is: Paris, London, Madrid. The program then compares the distance chooses two random points (cities) and swaps them around. eg say the
against the record distance to decide whether the new order is better than the old order. This search method order was London, Paris, Madrid, the program would swap London and Paris
is the most inefficient way, the worst case scenario is never ending, as the point swaping is random the so that the new order is: Paris, London, Madrid. The program then
program may never reach the optimum route</p><br> compares the distance against the record distance to decide whether the
<h3>Lexicographic Order</h3> new order is better than the old order. This search method is the most
<span id="c2"></span> inefficient way, the worst case scenario is never ending, as the point
<p class="canvasText">This canvas sorts through all possible orders sequentially, so after n! (where n is the swaping is random the program may never reach the optimum route
number of points) this algorithm is guaranteed to have found the quickest possible route. However it is </p>
highly inefficient always taking n! frames to complete and as n increases, time taken increases <br />
exponentially.</p> <h3>Lexicographic Order</h3>
<a target="_blank" <span id="c2"></span>
href="https://www.quora.com/How-would-you-explain-an-algorithm-that-generates-permutations-using-lexicographic-ordering">Click <p class="canvasText">
here to learn more about the algorithm</a><br> This canvas sorts through all possible orders sequentially, so after n!
<h3>Genetic Algorithm</h3> (where n is the number of points) this algorithm is guaranteed to have
<span id="c3"></span> found the quickest possible route. However it is highly inefficient
<p class="canvasText">This canvas is the most efficient at finding the quickest route, it is a mixture of the always taking n! frames to complete and as n increases, time taken
two methods above. It starts off by creating a population of orders, a fitness is then generated for each increases exponentially.
order in the population. This fitness decides how likely the order is to be picked and is based on the </p>
distance it takes (lower distance is better). When two orders are picked, the algorithm splices the two <a
together at a random term, it's then mutated and compared against the record distance. This takes the least target="_blank"
amount of time to find the shortest distance as the algorithm doesn't search through permuations that are href="https://www.quora.com/How-would-you-explain-an-algorithm-that-generates-permutations-using-lexicographic-ordering"
obviously longer due to the order.</p><br> >Click here to learn more about the algorithm</a
><br />
<h3>Genetic Algorithm</h3>
<span id="c3"></span>
<p class="canvasText">
This canvas is the most efficient at finding the quickest route, it is a
mixture of the two methods above. It starts off by creating a population
of orders, a fitness is then generated for each order in the population.
This fitness decides how likely the order is to be picked and is based
on the distance it takes (lower distance is better). When two orders are
picked, the algorithm splices the two together at a random term, it's
then mutated and compared against the record distance. This takes the
least amount of time to find the shortest distance as the algorithm
doesn't search through permuations that are obviously longer due to the
order.
</p>
<br />
</div> </div>
</body> </body>
<script src="sketch.js"></script> <script src="sketch.js"></script>
<footer>
<p>This page was inspired by The Coding Train</p><a
href="https://www.youtube.com/channel/UCvjgXvBlbQiydffZU7m1_aw">Check him out here</a>
</footer>
<footer>
<p>This page was inspired by The Coding Train</p>
<a href="https://www.youtube.com/channel/UCvjgXvBlbQiydffZU7m1_aw"
>Check him out here</a
>
</footer>
</html> </html>

View File

@@ -1,15 +1,18 @@
@import url('https://fonts.googleapis.com/css?family=Roboto+Condensed'); @import url("https://fonts.googleapis.com/css?family=Roboto+Condensed");
a{font-family: 'Roboto Condensed', sans-serif; font-size: 18pt;} a {
font-family: "Roboto Condensed", sans-serif;
font-size: 18pt;
}
h1 { h1 {
font-family: 'Roboto Condensed', sans-serif; font-family: "Roboto Condensed", sans-serif;
margin: 0; margin: 0;
padding: 0 0 15px 0; padding: 0 0 15px 0;
} }
h2 { h2 {
font-family: 'Roboto Condensed', sans-serif; font-family: "Roboto Condensed", sans-serif;
margin: 0; margin: 0;
padding: 0 0 15px 0; padding: 0 0 15px 0;
text-align: center; text-align: center;
@@ -17,89 +20,150 @@ h2 {
} }
@media (min-width: 350px) { @media (min-width: 350px) {
h1 {font-size: 3.25em;} h1 {
img{height: 40px;} font-size: 3.25em;
p{font-size: 10px;} }
h2{font-size: 17px;} img {
height: 40px;
}
p {
font-size: 10px;
}
h2 {
font-size: 17px;
}
} }
@media (min-width: 400px) { @media (min-width: 400px) {
h1 {font-size: 3.25em;} h1 {
img{height: 45px;} font-size: 3.25em;
p{font-size: 15px;} }
h2{font-size: 17px;} img {
height: 45px;
}
p {
font-size: 15px;
}
h2 {
font-size: 17px;
}
} }
@media (min-width: 440px) { @media (min-width: 440px) {
h1 {font-size: 3.5em;} h1 {
img {height: 100px;} font-size: 3.5em;
p{font-size: 16px;} }
h2{font-size: 18px;} img {
height: 100px;
}
p {
font-size: 16px;
}
h2 {
font-size: 18px;
}
} }
@media (min-width: 500px) { @media (min-width: 500px) {
h1 {font-size: 3.75em;} h1 {
img{height: 125px;} font-size: 3.75em;
p{font-size: 16px;} }
h2{font-size: 19px;} img {
height: 125px;
}
p {
font-size: 16px;
}
h2 {
font-size: 19px;
}
} }
@media (min-width: 630px) { @media (min-width: 630px) {
h1 {font-size: 5em;} h1 {
img{height: 150px;} font-size: 5em;
p{font-size: 20px;} }
h2{font-size: 24px;} img {
height: 150px;
}
p {
font-size: 20px;
}
h2 {
font-size: 24px;
}
} }
@media (min-width: 768px) { @media (min-width: 768px) {
h1 { h1 {
font-size: 5em; font-size: 5em;
padding-bottom: 30px; padding-bottom: 30px;
} }
img{height: 175px;} img {
p{font-size: 22px;} height: 175px;
h2{font-size: 26px;} }
p {
font-size: 22px;
}
h2 {
font-size: 26px;
}
} }
@media (min-width: 1200px) { @media (min-width: 1200px) {
h1 {font-size: 8em;} h1 {
img{height: 250px;} font-size: 8em;
p{font-size: 24px;} }
h2{font-size: 28px;} img {
height: 250px;
}
p {
font-size: 24px;
}
h2 {
font-size: 28px;
}
} }
p{ p {
font-family: "Roboto Condensed", sans-serif;
font-family: 'Roboto Condensed', sans-serif;
} }
h3{ h3 {
text-align: center; text-align: center;
font-size: 30px; font-size: 30px;
font-family: 'Roboto Condensed', sans-serif; font-family: "Roboto Condensed", sans-serif;
} }
footer{ footer {
padding: 20px; padding: 20px;
background-color: #e0e0e0; background-color: #e0e0e0;
font-family: 'Roboto Condensed', sans-serif; font-family: "Roboto Condensed", sans-serif;
} }
@keyframes dimImg{ @keyframes dimImg {
from {opacity: 1; from {
filter: alpha(opacity=100);} opacity: 1;
to {opacity: 0.4; filter: alpha(opacity=100);
filter: alpha(opacity=50);} }
to {
opacity: 0.4;
filter: alpha(opacity=50);
}
} }
@keyframes revealText{ @keyframes revealText {
from {opacity: 0.4; from {
filter: alpha(opacity=50);} opacity: 0.4;
to {opacity: 1; filter: alpha(opacity=50);
filter: alpha(opacity=100);} }
to {
opacity: 1;
filter: alpha(opacity=100);
}
} }
.pictureContainer{ .pictureContainer {
float: right; float: right;
position: relative; position: relative;
} }
.pictureContainer a{ .pictureContainer a {
opacity: 0; opacity: 0;
position: absolute; position: absolute;
text-align: center; text-align: center;
@@ -107,36 +171,36 @@ footer{
left: 5px; left: 5px;
} }
.pictureContainer:hover img {
.pictureContainer:hover img{
animation-name: dimImg; animation-name: dimImg;
animation-duration: 1s; animation-duration: 1s;
opacity: 0.4; opacity: 0.4;
filter: alpha(opacity=50); filter: alpha(opacity=50);
} }
.pictureContainer:hover a{ .pictureContainer:hover a {
animation-name: revealText; animation-name: revealText;
animation-duration: 1s; animation-duration: 1s;
opacity: 1; opacity: 1;
} }
.canvasText{ .canvasText {
margin: 0px; margin: 0px;
display: inline-block; display: inline-block;
text-align: left; text-align: left;
} }
#c1, #c2, #c3{ #c1,
#c2,
#c3 {
display: block; display: block;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
width: 50%; width: 50%;
} }
.button{ .button {
padding: 16px 32px; padding: 16px 32px;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
@@ -156,5 +220,3 @@ footer{
background-color: #555555; background-color: #555555;
color: white; color: white;
} }