From 13c8b0a28e01bdd37694ad14a3b6801be154da0c Mon Sep 17 00:00:00 2001 From: Jay Date: Sat, 21 Mar 2026 15:05:08 +0000 Subject: [PATCH] formatting --- 404.css | 210 ++-- 404.html | 121 +- 404.js | 2 +- index.html | 1011 +++++++++------- projects/cubic_bezier_curve/index.html | 19 +- projects/ellipse_construction.html | 357 +++--- projects/flocking/index.html | 164 +-- projects/fourier_series.html | 188 ++- projects/marching_squares.html | 407 ++++--- projects/maze_generation/index.html | 64 +- projects/percolation/index.html | 127 +- projects/percolation/style.css | 232 ++-- projects/pi_approximation.html | 117 +- projects/poisson_distribution.html | 151 ++- projects/thin_ice/thin_ice.html | 137 ++- projects/tsp/index.html | 147 ++- projects/tsp/style.css | 1 - projects/warping_lines.html | 326 ++--- style.css | 1314 +++++++++++---------- tutorials/convex_hull/index.html | 2 +- tutorials/convex_hull/style.css | 100 +- tutorials/midpoint_displacement/style.css | 100 +- tutorials/summed_area/index.html | 104 +- tutorials/summed_area/style.css | 57 +- tutorials/tsp/index.html | 165 ++- tutorials/tsp/style.css | 184 ++- 26 files changed, 3176 insertions(+), 2631 deletions(-) diff --git a/404.css b/404.css index f2a4648..c40b8c4 100644 --- a/404.css +++ b/404.css @@ -1,171 +1,171 @@ body { - display: flex; - flex-direction: column; - min-height: 100vh; + display: flex; + flex-direction: column; + min-height: 100vh; } .not-found { - flex: 1; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - padding: 7rem 2rem 5rem; - gap: 0; - position: relative; + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: 7rem 2rem 5rem; + gap: 0; + position: relative; } .nf-code { - font-family: 'Fraunces', serif; - font-size: clamp(7rem, 22vw, 16rem); - font-weight: 600; - line-height: 1; - color: var(--surface0); - letter-spacing: -0.02em; - user-select: none; - position: relative; - opacity: 0; - animation: fadeUp 0.6s 0.1s forwards; + font-family: "Fraunces", serif; + font-size: clamp(7rem, 22vw, 16rem); + font-weight: 600; + line-height: 1; + color: var(--surface0); + letter-spacing: -0.02em; + user-select: none; + position: relative; + opacity: 0; + animation: fadeUp 0.6s 0.1s forwards; } - .nf-eyebrow { - font-size: 0.7rem; - letter-spacing: 0.2em; - text-transform: uppercase; - color: var(--mauve); - margin-bottom: 0.75rem; - display: flex; - align-items: center; - gap: 0.75rem; - opacity: 0; - animation: fadeUp 0.6s 0.3s forwards; + font-size: 0.7rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--mauve); + margin-bottom: 0.75rem; + display: flex; + align-items: center; + gap: 0.75rem; + opacity: 0; + animation: fadeUp 0.6s 0.3s forwards; } .nf-eyebrow::before, .nf-eyebrow::after { - content: ''; - display: block; - height: 1px; - width: 3rem; - background: var(--mauve); - opacity: 0.5; + content: ""; + display: block; + height: 1px; + width: 3rem; + background: var(--mauve); + opacity: 0.5; } .nf-heading { - font-family: 'Fraunces', serif; - font-size: clamp(1.6rem, 4vw, 2.8rem); - font-weight: 600; - color: var(--text); - line-height: 1.15; - margin-bottom: 1rem; - opacity: 0; - animation: fadeUp 0.6s 0.4s forwards; + font-family: "Fraunces", serif; + font-size: clamp(1.6rem, 4vw, 2.8rem); + font-weight: 600; + color: var(--text); + line-height: 1.15; + margin-bottom: 1rem; + opacity: 0; + animation: fadeUp 0.6s 0.4s forwards; } .nf-heading em { - font-style: italic; - color: var(--mauve); + font-style: italic; + color: var(--mauve); } .nf-desc { - font-size: 0.88rem; - color: var(--subtext0); - max-width: 420px; - line-height: 1.8; - margin-bottom: 2.5rem; - opacity: 0; - animation: fadeUp 0.6s 0.5s forwards; + font-size: 0.88rem; + color: var(--subtext0); + max-width: 420px; + line-height: 1.8; + margin-bottom: 2.5rem; + opacity: 0; + animation: fadeUp 0.6s 0.5s forwards; } .nf-terminal { - background: var(--mantle); - border: 1px solid var(--surface0); - border-radius: 8px; - padding: 1rem 1.5rem; - font-size: 0.78rem; - color: var(--subtext1); - text-align: left; - max-width: 440px; - width: 100%; - margin-bottom: 2.5rem; - opacity: 0; - animation: fadeUp 0.6s 0.6s forwards; + background: var(--mantle); + border: 1px solid var(--surface0); + border-radius: 8px; + padding: 1rem 1.5rem; + font-size: 0.78rem; + color: var(--subtext1); + text-align: left; + max-width: 440px; + width: 100%; + margin-bottom: 2.5rem; + opacity: 0; + animation: fadeUp 0.6s 0.6s forwards; } .nf-terminal-bar { - display: flex; - gap: 0.5rem; - margin-bottom: 0.75rem; + display: flex; + gap: 0.5rem; + margin-bottom: 0.75rem; } .nf-dot { - width: 10px; - height: 10px; - border-radius: 50%; + width: 10px; + height: 10px; + border-radius: 50%; } .nf-dot--red { - background: var(--red); - opacity: 0.7; + background: var(--red); + opacity: 0.7; } .nf-dot--yellow { - background: var(--yellow); - opacity: 0.7; + background: var(--yellow); + opacity: 0.7; } .nf-dot--green { - background: var(--green); - opacity: 0.7; + background: var(--green); + opacity: 0.7; } .nf-terminal-line { - display: flex; - gap: 0.6rem; - line-height: 1.9; + display: flex; + gap: 0.6rem; + line-height: 1.9; } .nf-prompt { - color: var(--green); + color: var(--green); } .nf-cmd { - color: var(--text); + color: var(--text); } .nf-err { - color: var(--red); + color: var(--red); } .nf-comment { - color: var(--overlay1); + color: var(--overlay1); } .nf-cursor { - display: inline-block; - width: 0.55em; - height: 1em; - background: var(--mauve); - vertical-align: text-bottom; - animation: blink 1.1s step-end infinite; + display: inline-block; + width: 0.55em; + height: 1em; + background: var(--mauve); + vertical-align: text-bottom; + animation: blink 1.1s step-end infinite; } @keyframes blink { - 0%, 100% { - opacity: 1; - } - 50% { - opacity: 0; - } + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0; + } } .nf-actions { - display: flex; - gap: 1.25rem; - flex-wrap: wrap; - justify-content: center; - opacity: 0; - animation: fadeUp 0.6s 0.7s forwards; + display: flex; + gap: 1.25rem; + flex-wrap: wrap; + justify-content: center; + opacity: 0; + animation: fadeUp 0.6s 0.7s forwards; } diff --git a/404.html b/404.html index 95815ee..8f3b9db 100644 --- a/404.html +++ b/404.html @@ -1,83 +1,86 @@ - + - - - - + + + 404 — Havox - - + + - - - + 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" + /> + + + - - - - - -
+ +
+
404
-
404
+

page not found

+

This page doesn't exist

+

+ 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. +

-

page not found

-

This page doesn't exist

-

- 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. -

- -
-
+ + - - - - - - + + - diff --git a/404.js b/404.js index 94e6d9d..027fb96 100644 --- a/404.js +++ b/404.js @@ -19,4 +19,4 @@ }, 300); } }, 45); -})(); \ No newline at end of file +})(); diff --git a/index.html b/index.html index f6b3e8b..4e569b1 100644 --- a/index.html +++ b/index.html @@ -1,471 +1,686 @@ - + - - - - + + + Havox - - + + - - + 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" + /> + + - - - - - -
-

// havox.org - v4

-

John Gatward

-

Software Engineer

-

- - - -

- +
-
+
- -
-
+ +
+

Havox & me

-
- -
+
+
-
+
+
+

+ Havox started in 2017 as a place to dump whatever projects I had + written. Four redesigns and several dead domains later, it's still + going. Less a portfolio, more a scrapbook. +

+
-
-

Havox started in 2017 as a place to dump whatever projects I had written. Four redesigns and several - dead domains later, it's still going. Less a portfolio, more a scrapbook.

-
+
+ day job +

+ Backend engineer at Sainsbury's Supply Chain + & Logistics. It's good fun. +

+
-
- day job -

Backend engineer at Sainsbury's Supply Chain & Logistics. It's good fun.

-
- -
- dev -

Fascinated with new languages, frameworks, and shiny tech I probably don’t need. Constantly - learning just enough to build something slightly cooler next time.

-
- -
- linux -

Long-time Linux user and distro-hopper. Self-hosted server running 24/7 for friends and family who - didn't ask for it but probably definitely appreciate it.

-
+
+ dev +

+ Fascinated with new languages, frameworks, and shiny tech I + probably don’t need. Constantly learning just enough to build + something slightly cooler next time. +

+
+
+ linux +

+ Long-time Linux user and distro-hopper. Self-hosted server running + 24/7 for friends and family who didn't ask for it but + probably definitely appreciate it. +

+
-
-
+
-
+ +
+ +

+ What I know +

-
- - -
- -

What I know

- -
+
- -

Backend

-

Professional experience designing, building and deploying services. Using a modern tech stack in the - Supply Chain & Logistics industry.

-
- Java - Spring Boot - AWS - Kafka - MongoDB -
+ +

Backend

+

+ Professional experience designing, building and deploying services. + Using a modern tech stack in the Supply Chain & Logistics industry. +

+
+ Java + Spring Boot + AWS + Kafka + MongoDB +
-
- 🎨 -

Frontend & Creative

-

Comfortable with React and CSS. I've always enjoyed visualising algorithms interactively - it's way more - fun than a console output.

-
- React - TypeScript - HTML/CSS -
+
+ 🎨 +

Frontend & Creative

+

+ Comfortable with React and CSS. I've always enjoyed visualising + algorithms interactively - it's way more fun than a console output. +

+
+ React + TypeScript + HTML/CSS +
-
- 🖥 -

Systems & Infra

-

Long-term Linux & Vim user. Self-hosted web & media servers. Using industry practices when it comes to - networks & security.

-
- Linux - Docker - Self-Hosting - Wireguard -
+
+ 🖥 +

Systems & Infra

+

+ Long-term Linux & Vim user. Self-hosted web & media servers. Using + industry practices when it comes to networks & security. +

+
+ Linux + Docker + Self-Hosting + Wireguard +
-
- 🎓 -

Academic Breadth

-

C, C++, x86_64 assembly, Haskell, R & MatLab from uni. Modules in Advanced networking, - algorithms, compilers, - graphics, cryptography, malware analysis & many more.

-
- C / C++ - Haskell - Algorithms - Security - Low Level OS -
+
+ 🎓 +

Academic Breadth

+

+ C, C++, x86_64 assembly, Haskell, R & MatLab from uni. Modules + in Advanced networking, algorithms, compilers, graphics, + cryptography, malware analysis & many more. +

+
+ C / C++ + Haskell + Algorithms + Security + Low Level OS +
-
-
+ +
-
+
- -
- -

Things I built

-

- A timeline of my projects and an overview of my journey as a developer. Often times getting inspired and trying - to recreate something cool I saw. -

+ +
+ +

+ Things I built +

+

+ A timeline of my projects and an overview of my journey as a developer. + Often times getting inspired and trying to recreate something cool I + saw. +

-
+
Featured projects -
+
- -
+
All projects -
+
-
- - - - - - - +
+ + + + + + + - -
+ +
-
-
-
- -
-
+
+ +
+
-
+
- -
- -
+ +
+ +
-

Let's talk

-

- I am currently employed and open to the right software engineering opportunity, particularly - backend or full-stack roles with friendly, close-knit teams. -

-

- For professional enquiries, please contact me on LinkedIn. -

+

Let's talk

+

+ I am currently employed and open to the right software engineering + opportunity, particularly backend or full-stack roles with friendly, + close-knit teams. +

+

For professional enquiries, please contact me on LinkedIn.

-
-
+
+
- - - - - + + + + diff --git a/projects/cubic_bezier_curve/index.html b/projects/cubic_bezier_curve/index.html index 5845d78..edbac31 100644 --- a/projects/cubic_bezier_curve/index.html +++ b/projects/cubic_bezier_curve/index.html @@ -1,15 +1,18 @@ - + - - - + + - - - - + + diff --git a/projects/ellipse_construction.html b/projects/ellipse_construction.html index 3403d16..b3c0a5e 100755 --- a/projects/ellipse_construction.html +++ b/projects/ellipse_construction.html @@ -1,184 +1,191 @@ - - + + + + + - - - + + +
+

Ellipse Construction

+ +

+ Inspired by a Richard Feyman's + lost lecture + & + 3blue1brown's video. +

+

A geometric proof as to why planetary orbits are ellipitcal.

+ +

+

+
+ + - - + function getDist(x1, x2, y1, y2) { + return Math.sqrt((x1 - x2) ^ (2 + (y1 - y2)) ^ 2); + } + + diff --git a/projects/flocking/index.html b/projects/flocking/index.html index e9e4866..d2c770c 100644 --- a/projects/flocking/index.html +++ b/projects/flocking/index.html @@ -1,78 +1,106 @@ - + - - - + + + Flocking Boids - WASM - - - + + +
- -
+ - + - diff --git a/projects/fourier_series.html b/projects/fourier_series.html index 2aade60..26eca8b 100755 --- a/projects/fourier_series.html +++ b/projects/fourier_series.html @@ -1,122 +1,120 @@ - + - - + Fourier Series — Epicycles (p5.js) - + - - +
-

Fourier Series

-

- This interactive sketch visualizes a Fourier series using epicycles. Each circle represents - an odd harmonic; as you add more epicycles with the slider, the path on the right converges toward a - square wave. The rotating vectors sum to a point whose vertical position is traced over time. -

+

Fourier Series

+

+ This interactive sketch visualizes a Fourier series using epicycles. + Each circle represents an odd harmonic; as you add more epicycles with + the slider, the path on the right converges toward a square wave. The + rotating vectors sum to a point whose vertical position is traced over + time. +

-
-
+
- - + diff --git a/projects/marching_squares.html b/projects/marching_squares.html index c05c7b6..dcbee70 100755 --- a/projects/marching_squares.html +++ b/projects/marching_squares.html @@ -1,224 +1,247 @@ - + - - - + + + - - - - +
-

Marching Squares Field Visualizer

-

- This sketch uses the Marching Squares algorithm to generate and display contour boundaries - on a grid. Each cell is either active or inactive, the algorithm determines the correct line or triangle to - draw based on the surrounding corners. -

-

- Left-click toggles a cell between the two states. -

-

- Right‑click shows or hides the contour lines produced by the algorithm. -

+

Marching Squares Field Visualizer

+

+ This sketch uses the Marching Squares algorithm to + generate and display contour boundaries on a grid. Each cell is either + active or inactive, the algorithm determines the correct line or + triangle to draw based on the surrounding corners. +

+

Left-click toggles a cell between the two states.

+

+ Right‑click shows or hides the contour lines produced by the + algorithm. +

- - + diff --git a/projects/maze_generation/index.html b/projects/maze_generation/index.html index db64457..ec8a075 100644 --- a/projects/maze_generation/index.html +++ b/projects/maze_generation/index.html @@ -1,12 +1,17 @@ - - - + + @@ -14,39 +19,34 @@ Maze Generator - + - -
+

Maze Generator

-

- Toy maze generator using DFS & recursice back tracking. -

+

Toy maze generator using DFS & recursice back tracking.

-
- - - +
+ diff --git a/projects/percolation/index.html b/projects/percolation/index.html index 56a831e..fc69ce1 100644 --- a/projects/percolation/index.html +++ b/projects/percolation/index.html @@ -1,73 +1,82 @@ - + - - - + + + Percolation - - - + + +
- ← Back + ← Back -
-

Percolation

-

A simulation written in C & Raylib.

-
+
+

Percolation

+

A simulation written in C & Raylib.

+
-
-

- Percolation is a simple model for connectivity on a grid. Each cell is either open or closed. - This simulation stops as soon as there is a path from the top of the grid to the bottom through the open cells. -

-
-

- In this simulation, cells are randomly opened on a grid. Percolation occurs when there exists - a connected path of open cells from the top to the bottom of the grid. It is a neat way to visualise - threshold behaviour: below a certain probability nothing connects, and above it large connected regions - suddenly begin to appear. -

-
-
+
+

+ Percolation is a simple model for connectivity on a + grid. Each cell is either open or closed. This simulation stops as + soon as there is a path from the top of the grid to the bottom through + the open cells. +

+
+

+ In this simulation, cells are randomly opened on a grid. Percolation + occurs when there exists a connected path of open cells from the top + to the bottom of the grid. It is a neat way to visualise threshold + behaviour: below a certain probability nothing connects, and above + it large connected regions suddenly begin to appear. +

+
+
-
-
-

Canvas

- -
- -
- -
- -
Downloading...
- - -
- Show console output - - -
+
+
+

Canvas

+
-
-

Technical Details

-

- The simulation uses a disjoint-set (Union-Find) 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. -

-

- This makes each update fast and scalable even for larger grids. -

-
+
+ +
-
-

Built with C, Raylib, and WebAssembly

-
+
Downloading...
+ + +
+ Show console output + + +
+
+ +
+

Technical Details

+

+ The simulation uses a disjoint-set (Union-Find) 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. +

+

This makes each update fast and scalable even for larger grids.

+
+ +
+

Built with C, Raylib, and WebAssembly

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

+

-

-

- - + - -
+

Monte Carlo π Estimator

- A small demonstation on how the Monte Carlo method can approximate the value of π - by randomly placing points inside a square and checking how many fall within - the inner circle. The closer the ratio gets to π/4, the more accurate - the estimation becomes. + A small demonstation on how the Monte Carlo method can approximate the + value of π by randomly placing points inside a square and checking how + many fall within the inner circle. The closer the ratio gets to π/4, the + more accurate the estimation becomes.

-
+
- - - + diff --git a/projects/poisson_distribution.html b/projects/poisson_distribution.html index 9eeefa2..d6240a8 100644 --- a/projects/poisson_distribution.html +++ b/projects/poisson_distribution.html @@ -1,7 +1,7 @@ - + - - + - + diff --git a/projects/thin_ice/thin_ice.html b/projects/thin_ice/thin_ice.html index df72905..5833ebc 100644 --- a/projects/thin_ice/thin_ice.html +++ b/projects/thin_ice/thin_ice.html @@ -1,72 +1,91 @@ - - - - - Thin Ice | havox - - - -
- ← Back + + + + + Thin Ice | havox + + + +
+ ← Back -
-

Thin Ice

-

Inspired by Club Penguin's Thin Ice mini-game.

-
+
+

Thin Ice

+

Inspired by Club Penguin's Thin Ice mini-game.

+
-
-

- You start on safe ice, breaking ice where you walk, trying to reach the finish tile before trapping yourself. -

-
+

- 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.

-
-
+
+

+ See if you can get a gold medal on all 6 levels by breaking every + single tile of ice! +

+
+ -
-
-

Game

- +
+
+

Game

+ +
+ +
+ +
+ +
+ + +
+ +
Downloading...
+ + +
+ Show console output + + +
-
- -
+
+

How to Play

+
    +
  • Use WASM keys to move across the ice.
  • +
  • Plan ahead so you do not strand yourself on broken tiles.
  • +
  • Reach the end tile without falling into the water.
  • +
+
-
- - -
- -
Downloading...
- - -
- Show console output - - -
+
+

Built with C++ & Raylib, compiled to WASM with emscripten.

+
-
-

How to Play

-
    -
  • Use WASM keys to move across the ice.
  • -
  • Plan ahead so you do not strand yourself on broken tiles.
  • -
  • Reach the end tile without falling into the water.
  • -
-
- -
-

Built with C++ & Raylib, compiled to WASM with emscripten.

-
-
- - - - + + + diff --git a/projects/tsp/index.html b/projects/tsp/index.html index 79e77ae..b4990ab 100644 --- a/projects/tsp/index.html +++ b/projects/tsp/index.html @@ -1,74 +1,107 @@ - + - - - + + + Travelling Salesman Problem - - + +
- ← Back + ← Back -
-

Travelling Salesman Problem

-

An interactive route visualiser built with WebGL and WebAssembly.

-
+
+

Travelling Salesman Problem

+

+ An interactive route visualiser built with WebGL and WebAssembly. +

+
-
-

- After writing one of my first tutorials on the Travelling Salesman Problem, I wanted to revisit it with a slightly more technical stack. - The backend is written in Zig (compiled to WebAssembly), and the rendering is done directly in WebGL instead of p5.js or Raylib. -

+
+

+ After writing one of my first tutorials on the Travelling Salesman + Problem, I wanted to revisit it with a slightly more technical stack. + The backend is written in Zig (compiled to WebAssembly), and the + rendering is done directly in WebGL instead of p5.js or Raylib. +

+

+ This project was also inspired by + sphaerophoria who + started a + series + on creating his own map. +

+ +

- This project was also inspired by sphaerophoria who started a series on creating his own map. + Drag points around the canvas and watch the route update in real + time.

+
+
-
-

- Drag points around the canvas and watch the route update in real time. -

-
-
- -
-
-
- - - -
-
- -
- - HTML5 canvas not supported in browser - -
- -
-
36 points
-

Tip: click and drag a point to recompute the route.

-
+
+
+
+ + + +
-
-

Technical Details

-

- 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. -

-

- 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. -

-
+
+ + HTML5 canvas not supported in browser + +
-
-

Built with Zig, WebGL2 and WebAssembly

-
+
+
36 points
+

+ Tip: click and drag a point to recompute the route. +

+
+
+ +
+

Technical Details

+

+ 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. +

+

+ 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. +

+
+ +
+

Built with Zig, WebGL2 and WebAssembly

+
- + diff --git a/projects/tsp/style.css b/projects/tsp/style.css index 5582b95..4fccbca 100644 --- a/projects/tsp/style.css +++ b/projects/tsp/style.css @@ -199,4 +199,3 @@ footer { height: 400px; } } - diff --git a/projects/warping_lines.html b/projects/warping_lines.html index 3336e96..33e906a 100755 --- a/projects/warping_lines.html +++ b/projects/warping_lines.html @@ -1,166 +1,222 @@ - + - - - + + - - - + +
-

Oscillating Arrow Field Visualizer

-

- A sketch to hopefully demonstrate the illusion of the Müller-Lyer Illusion -

-

The lines - that are the same length, should look longer and shorter based on the angle of the arrow heads. -

-

- Increasing the value adds more horizontal slices, creating a denser and more detailed pattern. - Tap or click to pause and resume the motion. -

+

Oscillating Arrow Field Visualizer

+

+ A sketch to hopefully demonstrate the illusion of the + Müller-Lyer Illusion +

+

+ The lines - that are the same length, should look longer and shorter + based on the angle of the arrow heads. +

+

+ Increasing the value adds more horizontal slices, creating a denser and + more detailed pattern. Tap or click to pause and resume the motion. +

- +
- - + diff --git a/style.css b/style.css index f9501c0..cb895dc 100644 --- a/style.css +++ b/style.css @@ -1,1082 +1,1126 @@ /* ─── Catppuccin Mocha ─────────────────────────────────── */ :root { - --base: #1e1e2e; - --mantle: #181825; - --crust: #11111b; - --surface0: #313244; - --surface1: #45475a; - --surface2: #585b70; - --overlay0: #6c7086; - --overlay1: #7f849c; - --overlay2: #9399b2; - --text: #cdd6f4; - --subtext0: #a6adc8; - --subtext1: #bac2de; - --lavender: #b4befe; - --blue: #89b4fa; - --sapphire: #74c7ec; - --sky: #89dceb; - --teal: #94e2d5; - --green: #a6e3a1; - --yellow: #f9e2af; - --peach: #fab387; - --maroon: #eba0ac; - --red: #f38ba8; - --mauve: #cba6f7; - --pink: #f5c2e7; - --flamingo: #f2cdcd; - --rosewater: #f5e0dc; + --base: #1e1e2e; + --mantle: #181825; + --crust: #11111b; + --surface0: #313244; + --surface1: #45475a; + --surface2: #585b70; + --overlay0: #6c7086; + --overlay1: #7f849c; + --overlay2: #9399b2; + --text: #cdd6f4; + --subtext0: #a6adc8; + --subtext1: #bac2de; + --lavender: #b4befe; + --blue: #89b4fa; + --sapphire: #74c7ec; + --sky: #89dceb; + --teal: #94e2d5; + --green: #a6e3a1; + --yellow: #f9e2af; + --peach: #fab387; + --maroon: #eba0ac; + --red: #f38ba8; + --mauve: #cba6f7; + --pink: #f5c2e7; + --flamingo: #f2cdcd; + --rosewater: #f5e0dc; } -*, *::before, *::after { - box-sizing: border-box; - margin: 0; - padding: 0; +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; } html { - scroll-behavior: smooth; + scroll-behavior: smooth; } body { - background: radial-gradient(rgba(205, 214, 244, 0.028) 0.5px, transparent 0.6px), + background: + radial-gradient(rgba(205, 214, 244, 0.028) 0.5px, transparent 0.6px), radial-gradient(rgba(17, 17, 27, 0.032) 0.5px, transparent 0.6px), - radial-gradient(1200px 800px at 12% 8%, rgba(137, 180, 250, 0.07), transparent 62%), - radial-gradient(1000px 720px at 88% 92%, rgba(203, 166, 247, 0.07), transparent 64%), + radial-gradient( + 1200px 800px at 12% 8%, + rgba(137, 180, 250, 0.07), + transparent 62% + ), + radial-gradient( + 1000px 720px at 88% 92%, + rgba(203, 166, 247, 0.07), + transparent 64% + ), linear-gradient(180deg, #1e1e2e 0%, #1b1b2b 55%, #1a1a29 100%); - background-size: 3px 3px, 3px 3px, auto, auto, auto; - background-position: 0 0, 1px 1px, 0 0, 0 0, 0 0; - color: var(--text); - font-family: 'JetBrains Mono', 'Apple Color Emoji', monospace; - font-size: 15px; - line-height: 1.7; - overflow-x: hidden; - position: relative; + background-size: + 3px 3px, + 3px 3px, + auto, + auto, + auto; + background-position: + 0 0, + 1px 1px, + 0 0, + 0 0, + 0 0; + color: var(--text); + font-family: "JetBrains Mono", "Apple Color Emoji", monospace; + font-size: 15px; + line-height: 1.7; + overflow-x: hidden; + position: relative; } body::before, body::after { - content: ''; - position: fixed; - width: 52rem; - height: 42rem; - border-radius: 58% 42% 55% 45% / 46% 54% 48% 52%; - pointer-events: none; - z-index: -1; - filter: blur(90px); - opacity: 0.16; + content: ""; + position: fixed; + width: 52rem; + height: 42rem; + border-radius: 58% 42% 55% 45% / 46% 54% 48% 52%; + pointer-events: none; + z-index: -1; + filter: blur(90px); + opacity: 0.16; } body::before { - top: -18rem; - right: -16rem; - transform: rotate(14deg); - background: radial-gradient(closest-side at 38% 42%, rgba(203, 166, 247, 0.42), transparent 72%); + top: -18rem; + right: -16rem; + transform: rotate(14deg); + background: radial-gradient( + closest-side at 38% 42%, + rgba(203, 166, 247, 0.42), + transparent 72% + ); } body::after { - bottom: -20rem; - left: -18rem; - transform: rotate(-12deg); - background: radial-gradient(closest-side at 60% 58%, rgba(137, 180, 250, 0.36), transparent 72%); + bottom: -20rem; + left: -18rem; + transform: rotate(-12deg); + background: radial-gradient( + closest-side at 60% 58%, + rgba(137, 180, 250, 0.36), + transparent 72% + ); } ::selection { - background: var(--mauve); - color: var(--crust); + background: var(--mauve); + color: var(--crust); } /* ─── Scrollbar ────────────────────────────────────────── */ ::-webkit-scrollbar { - width: 6px; + width: 6px; } ::-webkit-scrollbar-track { - background: var(--mantle); + background: var(--mantle); } ::-webkit-scrollbar-thumb { - background: var(--surface1); - border-radius: 3px; + background: var(--surface1); + border-radius: 3px; } ::-webkit-scrollbar-thumb:hover { - background: var(--mauve); + background: var(--mauve); } /* ─── Nav ──────────────────────────────────────────────── */ nav { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 100; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 3rem; - height: 56px; - background: rgba(17, 17, 27, 0.85); - backdrop-filter: blur(12px); - border-bottom: 1px solid var(--surface0); + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 3rem; + height: 56px; + background: rgba(17, 17, 27, 0.85); + backdrop-filter: blur(12px); + border-bottom: 1px solid var(--surface0); } .nav-logo { - font-family: 'Fraunces', serif; - font-size: 1.3rem; - color: var(--mauve); - text-decoration: none; - letter-spacing: 0.02em; + font-family: "Fraunces", serif; + font-size: 1.3rem; + color: var(--mauve); + text-decoration: none; + letter-spacing: 0.02em; } .nav-links { - display: flex; - gap: 2.5rem; - list-style: none; + display: flex; + gap: 2.5rem; + list-style: none; } .nav-links a { - color: var(--subtext0); - text-decoration: none; - font-size: 0.78rem; - letter-spacing: 0.08em; - text-transform: uppercase; - transition: color 0.2s; - position: relative; + color: var(--subtext0); + text-decoration: none; + font-size: 0.78rem; + letter-spacing: 0.08em; + text-transform: uppercase; + transition: color 0.2s; + position: relative; } .nav-links a::after { - content: ''; - position: absolute; - bottom: -3px; - left: 0; - right: 0; - height: 1px; - background: var(--mauve); - transform: scaleX(0); - transform-origin: left; - transition: transform 0.2s; + content: ""; + position: absolute; + bottom: -3px; + left: 0; + right: 0; + height: 1px; + background: var(--mauve); + transform: scaleX(0); + transform-origin: left; + transition: transform 0.2s; } .nav-links a:hover { - color: var(--text); + color: var(--text); } .nav-links a:hover::after { - transform: scaleX(1); + transform: scaleX(1); } /* ─── Sections ─────────────────────────────────────────── */ section { - min-height: 100vh; - padding: 7rem 3rem 5rem; - max-width: 1100px; - margin: 0 auto; + min-height: 100vh; + padding: 7rem 3rem 5rem; + max-width: 1100px; + margin: 0 auto; } section.full-width { - max-width: none; - padding-left: 0; - padding-right: 0; + max-width: none; + padding-left: 0; + padding-right: 0; } /* ─── Section labels ───────────────────────────────────── */ .section-label { - font-size: 0.7rem; - letter-spacing: 0.2em; - text-transform: uppercase; - color: var(--mauve); - margin-bottom: 0.5rem; - display: flex; - align-items: center; - gap: 0.75rem; + font-size: 0.7rem; + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--mauve); + margin-bottom: 0.5rem; + display: flex; + align-items: center; + gap: 0.75rem; } .section-label::after { - content: ''; - display: block; - height: 1px; - width: 3rem; - background: var(--mauve); - opacity: 0.5; + content: ""; + display: block; + height: 1px; + width: 3rem; + background: var(--mauve); + opacity: 0.5; } /* ─── Hero ─────────────────────────────────────────────── */ #hero { - min-height: 100vh; - display: flex; - flex-direction: column; - justify-content: center; - padding-top: 5rem; - position: relative; + min-height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + padding-top: 5rem; + position: relative; } .hero-eyebrow { - font-size: 0.75rem; - letter-spacing: 0.25em; - text-transform: uppercase; - color: var(--green); - margin-bottom: 1.5rem; - opacity: 0; - animation: fadeUp 0.6s 0.2s forwards; + font-size: 0.75rem; + letter-spacing: 0.25em; + text-transform: uppercase; + color: var(--green); + margin-bottom: 1.5rem; + opacity: 0; + animation: fadeUp 0.6s 0.2s forwards; } .hero-name { - font-family: 'Fraunces', serif; - font-size: clamp(3.5rem, 9vw, 7.5rem); - font-weight: 600; - line-height: 1; - color: var(--text); - margin-bottom: 0.5rem; - opacity: 0; - animation: fadeUp 0.7s 0.35s forwards; + font-family: "Fraunces", serif; + font-size: clamp(3.5rem, 9vw, 7.5rem); + font-weight: 600; + line-height: 1; + color: var(--text); + margin-bottom: 0.5rem; + opacity: 0; + animation: fadeUp 0.7s 0.35s forwards; } .hero-name em { - font-style: italic; - color: var(--mauve); + font-style: italic; + color: var(--mauve); } .hero-subtitle { - font-family: 'Fraunces', serif; - font-size: clamp(1.2rem, 3vw, 2.2rem); - font-weight: 300; - color: var(--subtext1); - margin-bottom: 2rem; - opacity: 0; - animation: fadeUp 0.7s 0.5s forwards; + font-family: "Fraunces", serif; + font-size: clamp(1.2rem, 3vw, 2.2rem); + font-weight: 300; + color: var(--subtext1); + margin-bottom: 2rem; + opacity: 0; + animation: fadeUp 0.7s 0.5s forwards; } .hero-desc { - max-width: 560px; - color: var(--subtext0); - font-size: 0.9rem; - line-height: 1.8; - margin-bottom: 2.5rem; - opacity: 0; - animation: fadeUp 0.7s 0.65s forwards; + max-width: 560px; + color: var(--subtext0); + font-size: 0.9rem; + line-height: 1.8; + margin-bottom: 2.5rem; + opacity: 0; + animation: fadeUp 0.7s 0.65s forwards; } .hero-by-line { - display: flex; - align-items: baseline; - gap: 0.6rem; - margin-bottom: 0.3rem; + display: flex; + align-items: baseline; + gap: 0.6rem; + margin-bottom: 0.3rem; } .hero-by { - color: var(--text); - font-size: 0.9rem; + color: var(--text); + font-size: 0.9rem; } .hero-by-role { - font-family: 'Fraunces', serif; - font-style: italic; - font-size: 0.85rem; - color: var(--mauve); - opacity: 0.8; + font-family: "Fraunces", serif; + font-style: italic; + font-size: 0.85rem; + color: var(--mauve); + opacity: 0.8; } .hero-by-footer { - display: block; - margin-top: 1rem; - color: var(--subtext0); - font-size: 0.82rem; - opacity: 0.75; + display: block; + margin-top: 1rem; + color: var(--subtext0); + font-size: 0.82rem; + opacity: 0.75; } .hero-links { - display: flex; - gap: 1.25rem; - flex-wrap: wrap; - opacity: 0; - animation: fadeUp 0.7s 0.8s forwards; + display: flex; + gap: 1.25rem; + flex-wrap: wrap; + opacity: 0; + animation: fadeUp 0.7s 0.8s forwards; } .btn { - display: inline-flex; - align-items: center; - gap: 0.5rem; - padding: 0.6rem 1.4rem; - border-radius: 4px; - font-family: 'JetBrains Mono', monospace; - font-size: 0.78rem; - letter-spacing: 0.05em; - text-decoration: none; - transition: all 0.2s; - cursor: pointer; - border: none; + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.6rem 1.4rem; + border-radius: 4px; + font-family: "JetBrains Mono", monospace; + font-size: 0.78rem; + letter-spacing: 0.05em; + text-decoration: none; + transition: all 0.2s; + cursor: pointer; + border: none; } .btn-primary { - background: var(--mauve); - color: var(--crust); - box-shadow: 0 0 0 1px rgba(203, 166, 247, 0.25), 0 10px 26px rgba(17, 17, 27, 0.4); + background: var(--mauve); + color: var(--crust); + box-shadow: + 0 0 0 1px rgba(203, 166, 247, 0.25), + 0 10px 26px rgba(17, 17, 27, 0.4); } .btn-primary:hover { - background: var(--lavender); - transform: translateY(-2px); + background: var(--lavender); + transform: translateY(-2px); } .btn-ghost { - background: transparent; - color: var(--text); - border: 1px solid var(--surface1); + background: transparent; + color: var(--text); + border: 1px solid var(--surface1); } .btn-ghost:hover { - border-color: var(--mauve); - color: var(--mauve); - transform: translateY(-2px); + border-color: var(--mauve); + color: var(--mauve); + transform: translateY(-2px); } /* Decorative grid bg */ #hero::before { - content: ''; - position: absolute; - inset: 0; - background-image: linear-gradient(var(--surface0) 1px, transparent 1px), + content: ""; + position: absolute; + inset: 0; + background-image: + linear-gradient(var(--surface0) 1px, transparent 1px), linear-gradient(90deg, var(--surface0) 1px, transparent 1px); - background-size: 60px 60px; - opacity: 0.18; - mask-image: radial-gradient(ellipse 80% 60% at 50% 50%, black, transparent); - pointer-events: none; + background-size: 60px 60px; + opacity: 0.18; + mask-image: radial-gradient(ellipse 80% 60% at 50% 50%, black, transparent); + pointer-events: none; } /* ─── About ────────────────────────────────────────────── */ .about-section { - min-height: auto; - padding-bottom: 5rem; + min-height: auto; + padding-bottom: 5rem; } .about-columns { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 2rem; - margin-top: 2.5rem; - align-items: start; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 2rem; + margin-top: 2.5rem; + align-items: start; } .about-grid { - display: flex; - flex-direction: column; - border: 1px solid var(--surface0); - border-radius: 8px; - overflow: hidden; + display: flex; + flex-direction: column; + border: 1px solid var(--surface0); + border-radius: 8px; + overflow: hidden; } .about-block { - background: var(--mantle); - padding: 1.25rem 1.5rem; - border-bottom: 1px solid var(--surface0); - transition: background 0.2s; - display: flex; - align-items: baseline; - gap: 1.25rem; + background: var(--mantle); + padding: 1.25rem 1.5rem; + border-bottom: 1px solid var(--surface0); + transition: background 0.2s; + display: flex; + align-items: baseline; + gap: 1.25rem; } .about-grid .about-block:first-child { - background: linear-gradient(90deg, rgba(203, 166, 247, 0.07), rgba(203, 166, 247, 0.03)); - border-left: 2px solid rgba(203, 166, 247, 0.65); - box-shadow: inset 0 0 0 1px rgba(203, 166, 247, 0.08); + background: linear-gradient( + 90deg, + rgba(203, 166, 247, 0.07), + rgba(203, 166, 247, 0.03) + ); + border-left: 2px solid rgba(203, 166, 247, 0.65); + box-shadow: inset 0 0 0 1px rgba(203, 166, 247, 0.08); } .about-block:last-child { - border-bottom: none; + border-bottom: none; } .about-block-tag { - flex-shrink: 0; - font-size: 0.65rem; - letter-spacing: 0.1em; - text-transform: uppercase; - width: 5rem; - text-align: center; + flex-shrink: 0; + font-size: 0.65rem; + letter-spacing: 0.1em; + text-transform: uppercase; + width: 5rem; + text-align: center; } .about-block p { - color: var(--subtext0); - font-size: 0.85rem; - line-height: 1.75; + color: var(--subtext0); + font-size: 0.85rem; + line-height: 1.75; } .about-block p strong { - color: var(--text); - font-weight: 700; + color: var(--text); + font-weight: 700; } .about-block p em { - color: var(--mauve); - font-style: italic; + color: var(--mauve); + font-style: italic; } .about-block p s { - color: var(--overlay1); + color: var(--overlay1); } .version-timeline { - display: flex; - flex-direction: column; - gap: 0; - position: relative; + display: flex; + flex-direction: column; + gap: 0; + position: relative; } .version-timeline::before { - content: ''; - position: absolute; - left: 0.65rem; - top: 0.5rem; - bottom: 0.5rem; - width: 1px; - background: var(--surface1); + content: ""; + position: absolute; + left: 0.65rem; + top: 0.5rem; + bottom: 0.5rem; + width: 1px; + background: var(--surface1); } .version-item { - display: flex; - gap: 1.25rem; - padding: 1rem 0; - position: relative; + display: flex; + gap: 1.25rem; + padding: 1rem 0; + position: relative; } .v-dot { - width: 1.3rem; - height: 1.3rem; - border-radius: 50%; - background: var(--surface0); - border: 2px solid var(--surface1); - flex-shrink: 0; - margin-top: 0.15rem; - transition: border-color 0.2s, background 0.2s; - position: relative; - z-index: 1; + width: 1.3rem; + height: 1.3rem; + border-radius: 50%; + background: var(--surface0); + border: 2px solid var(--surface1); + flex-shrink: 0; + margin-top: 0.15rem; + transition: + border-color 0.2s, + background 0.2s; + position: relative; + z-index: 1; } .version-item:hover .v-dot { - border-color: var(--mauve); - background: var(--mauve); + border-color: var(--mauve); + background: var(--mauve); } .v-title { - font-size: 0.85rem; - font-weight: 700; - color: var(--text); - margin-bottom: 0.15rem; + font-size: 0.85rem; + font-weight: 700; + color: var(--text); + margin-bottom: 0.15rem; } .v-year { - font-size: 0.7rem; - color: var(--mauve); - margin-bottom: 0.3rem; - letter-spacing: 0.05em; + font-size: 0.7rem; + color: var(--mauve); + margin-bottom: 0.3rem; + letter-spacing: 0.05em; } .v-desc { - font-size: 0.8rem; - color: var(--subtext0); - line-height: 1.6; + font-size: 0.8rem; + color: var(--subtext0); + line-height: 1.6; } .version-item--link { - text-decoration: none; - color: inherit; - cursor: pointer; + text-decoration: none; + color: inherit; + cursor: pointer; } .version-item--link:hover .v-dot { - border-color: var(--mauve); - background: var(--mauve); + border-color: var(--mauve); + background: var(--mauve); } .version-item--link:hover .v-title { - color: var(--mauve); + color: var(--mauve); } .v-link-arrow { - font-size: 0.7rem; - color: var(--overlay1); - margin-left: 0.3rem; - transition: color 0.2s, transform 0.2s; - display: inline-block; + font-size: 0.7rem; + color: var(--overlay1); + margin-left: 0.3rem; + transition: + color 0.2s, + transform 0.2s; + display: inline-block; } .version-item--link:hover .v-link-arrow { - color: var(--mauve); - transform: translate(2px, -2px); + color: var(--mauve); + transform: translate(2px, -2px); } .v-dot--current { - border-color: var(--mauve); - background: var(--mauve); + border-color: var(--mauve); + background: var(--mauve); } .v-current-badge { - font-size: 0.6rem; - letter-spacing: 0.08em; - text-transform: uppercase; - background: rgba(203, 166, 247, 0.15); - color: var(--mauve); - padding: 0.1rem 0.45rem; - border-radius: 3px; - margin-left: 0.4rem; - vertical-align: middle; - font-weight: 700; + font-size: 0.6rem; + letter-spacing: 0.08em; + text-transform: uppercase; + background: rgba(203, 166, 247, 0.15); + color: var(--mauve); + padding: 0.1rem 0.45rem; + border-radius: 3px; + margin-left: 0.4rem; + vertical-align: middle; + font-weight: 700; } /* ─── Skills ───────────────────────────────────────────── */ #skills h2 { - font-family: 'Fraunces', serif; - font-size: 2.8rem; - font-weight: 600; - color: var(--text); - margin-bottom: 3rem; + font-family: "Fraunces", serif; + font-size: 2.8rem; + font-weight: 600; + color: var(--text); + margin-bottom: 3rem; } #skills h2 em { - font-style: italic; - color: var(--mauve); + font-style: italic; + color: var(--mauve); } .skills-grid { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 1px; - background: var(--surface0); - border: 1px solid var(--surface0); - border-radius: 8px; - overflow: hidden; + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1px; + background: var(--surface0); + border: 1px solid var(--surface0); + border-radius: 8px; + overflow: hidden; } .skill-card--wide { - grid-column: 1 / -1; + grid-column: 1 / -1; } .skill-card { - background: var(--mantle); - padding: 2rem; - transition: background 0.2s; + background: var(--mantle); + padding: 2rem; + transition: background 0.2s; } .skill-card-icon { - font-size: 1.5rem; - margin-bottom: 1rem; - display: block; + font-size: 1.5rem; + margin-bottom: 1rem; + display: block; } .skill-card h3 { - font-size: 0.85rem; - font-weight: 700; - color: var(--text); - margin-bottom: 0.5rem; - letter-spacing: 0.05em; - text-transform: uppercase; + font-size: 0.85rem; + font-weight: 700; + color: var(--text); + margin-bottom: 0.5rem; + letter-spacing: 0.05em; + text-transform: uppercase; } .skill-card p { - font-size: 0.82rem; - color: var(--subtext0); - line-height: 1.7; + font-size: 0.82rem; + color: var(--subtext0); + line-height: 1.7; } .tag-row { - display: flex; - flex-wrap: wrap; - gap: 0.4rem; - margin-top: 1rem; + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + margin-top: 1rem; } .tag { - display: inline-block; - padding: 0.15rem 0.6rem; - border-radius: 3px; - font-size: 0.7rem; - letter-spacing: 0.04em; - font-weight: 700; + display: inline-block; + padding: 0.15rem 0.6rem; + border-radius: 3px; + font-size: 0.7rem; + letter-spacing: 0.04em; + font-weight: 700; } .tag-blue { - background: rgba(137, 180, 250, 0.12); - color: var(--blue); + background: rgba(137, 180, 250, 0.12); + color: var(--blue); } .tag-green { - background: rgba(166, 227, 161, 0.12); - color: var(--green); + background: rgba(166, 227, 161, 0.12); + color: var(--green); } .tag-peach { - background: rgba(250, 179, 135, 0.12); - color: var(--peach); + background: rgba(250, 179, 135, 0.12); + color: var(--peach); } .tag-teal { - background: rgba(148, 226, 213, 0.12); - color: var(--teal); + background: rgba(148, 226, 213, 0.12); + color: var(--teal); } .tag-mauve { - background: rgba(203, 166, 247, 0.12); - color: var(--mauve); + background: rgba(203, 166, 247, 0.12); + color: var(--mauve); } .tag-yellow { - background: rgba(249, 226, 175, 0.12); - color: var(--yellow); + background: rgba(249, 226, 175, 0.12); + color: var(--yellow); } .tag-sky { - background: rgba(137, 220, 235, 0.12); - color: var(--sky); + background: rgba(137, 220, 235, 0.12); + color: var(--sky); } .tag-red { - background: rgba(243, 139, 168, 0.12); - color: var(--red); + background: rgba(243, 139, 168, 0.12); + color: var(--red); } .tag-pink { - background: rgba(245, 194, 231, 0.12); - color: var(--pink); + background: rgba(245, 194, 231, 0.12); + color: var(--pink); } /* ─── Tutorials / Projects shared ─────────────────────── */ .section-heading { - font-family: 'Fraunces', serif; - font-size: 2.8rem; - font-weight: 600; - color: var(--text); - margin-bottom: 0.75rem; + font-family: "Fraunces", serif; + font-size: 2.8rem; + font-weight: 600; + color: var(--text); + margin-bottom: 0.75rem; } .section-heading em { - font-style: italic; - color: var(--mauve); - text-shadow: 0 0 16px rgba(203, 166, 247, 0.25); + font-style: italic; + color: var(--mauve); + text-shadow: 0 0 16px rgba(203, 166, 247, 0.25); } .section-intro { - color: var(--subtext0); - font-size: 0.88rem; - max-width: 560px; - line-height: 1.8; - margin-bottom: 3rem; + color: var(--subtext0); + font-size: 0.88rem; + max-width: 560px; + line-height: 1.8; + margin-bottom: 3rem; } .projects-subheading { - margin: 0 0 0.9rem; - font-size: 0.7rem; - letter-spacing: 0.14em; - text-transform: uppercase; - color: var(--mauve); + margin: 0 0 0.9rem; + font-size: 0.7rem; + letter-spacing: 0.14em; + text-transform: uppercase; + color: var(--mauve); } .card-grid.card-grid--featured { - margin-bottom: 2rem; - grid-template-columns: repeat(2, minmax(0, 1fr)); + margin-bottom: 2rem; + grid-template-columns: repeat(2, minmax(0, 1fr)); } #projects .section-intro { - margin-bottom: 1.8rem; - max-width: 640px; + margin-bottom: 1.8rem; + max-width: 640px; } #project-grid { - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-columns: repeat(3, minmax(0, 1fr)); } #project-grid .card { - padding: 1.2rem; + padding: 1.2rem; } .project-filters { - display: flex; - flex-wrap: wrap; - gap: 0.5rem; - border: none; - padding: 0; - min-width: 0; - margin-bottom: 1.25rem; + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + border: none; + padding: 0; + min-width: 0; + margin-bottom: 1.25rem; } .filter-chip { - border: 1px solid var(--surface1); - background: var(--mantle); - color: var(--subtext0); - border-radius: 999px; - padding: 0.32rem 0.8rem; - font-size: 0.68rem; - letter-spacing: 0.04em; - text-transform: uppercase; - font-family: 'JetBrains Mono', monospace; - cursor: pointer; - transition: all 0.2s; + border: 1px solid var(--surface1); + background: var(--mantle); + color: var(--subtext0); + border-radius: 999px; + padding: 0.32rem 0.8rem; + font-size: 0.68rem; + letter-spacing: 0.04em; + text-transform: uppercase; + font-family: "JetBrains Mono", monospace; + cursor: pointer; + transition: all 0.2s; } .filter-chip:hover { - border-color: var(--mauve); - color: var(--text); + border-color: var(--mauve); + color: var(--text); } .filter-chip.active { - background: rgba(203, 166, 247, 0.18); - border-color: rgba(203, 166, 247, 0.7); - color: var(--mauve); + background: rgba(203, 166, 247, 0.18); + border-color: rgba(203, 166, 247, 0.7); + color: var(--mauve); } .card.is-hidden { - display: none; + display: none; } .card.is-collapsed { - display: none; + display: none; } .projects-more-row { - margin-top: 1rem; - display: flex; - justify-content: center; + margin-top: 1rem; + display: flex; + justify-content: center; } .projects-more-btn { - border: 1px solid var(--surface1); - background: var(--mantle); - color: var(--subtext0); - border-radius: 999px; - padding: 0.42rem 1rem; - font-size: 0.72rem; - letter-spacing: 0.06em; - text-transform: uppercase; - font-family: 'JetBrains Mono', monospace; - cursor: pointer; - transition: all 0.2s; + border: 1px solid var(--surface1); + background: var(--mantle); + color: var(--subtext0); + border-radius: 999px; + padding: 0.42rem 1rem; + font-size: 0.72rem; + letter-spacing: 0.06em; + text-transform: uppercase; + font-family: "JetBrains Mono", monospace; + cursor: pointer; + transition: all 0.2s; } .projects-more-btn:hover { - border-color: var(--mauve); - color: var(--text); + border-color: var(--mauve); + color: var(--text); } /* ─── Card grid ────────────────────────────────────────── */ .card-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 1px; - background: var(--surface0); - border: 1px solid var(--surface0); - border-radius: 8px; - overflow: hidden; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 1px; + background: var(--surface0); + border: 1px solid var(--surface0); + border-radius: 8px; + overflow: hidden; } .card { - background: var(--mantle); - padding: 1.5rem; - display: flex; - flex-direction: column; - gap: 0.5rem; - text-decoration: none; - color: inherit; - transition: background 0.2s; - position: relative; - overflow: hidden; + background: var(--mantle); + padding: 1.5rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + text-decoration: none; + color: inherit; + transition: background 0.2s; + position: relative; + overflow: hidden; } .card-link { - cursor: pointer; + cursor: pointer; } .card-link:focus-visible { - outline: 1px solid var(--mauve); - outline-offset: -1px; + outline: 1px solid var(--mauve); + outline-offset: -1px; } .card::before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 3px; - height: 100%; - background: var(--mauve); - transform: scaleY(0); - transform-origin: bottom; - transition: transform 0.25s; + content: ""; + position: absolute; + top: 0; + left: 0; + width: 3px; + height: 100%; + background: var(--mauve); + transform: scaleY(0); + transform-origin: bottom; + transition: transform 0.25s; } .card:hover { - background: var(--surface0); - transform: translateY(-1px); + background: var(--surface0); + transform: translateY(-1px); } .card:hover::before { - transform: scaleY(1); + transform: scaleY(1); } .card-date { - font-size: 0.68rem; - color: var(--overlay1); - letter-spacing: 0.06em; + font-size: 0.68rem; + color: var(--overlay1); + letter-spacing: 0.06em; } .card-title { - font-size: 0.92rem; - font-weight: 700; - color: var(--text); - transition: color 0.2s; + font-size: 0.92rem; + font-weight: 700; + color: var(--text); + transition: color 0.2s; } .card:hover .card-title { - color: var(--mauve); + color: var(--mauve); } .card-desc { - font-size: 0.8rem; - color: var(--subtext0); - line-height: 1.6; - flex: 1; + font-size: 0.8rem; + color: var(--subtext0); + line-height: 1.6; + flex: 1; } .card-desc a { - color: var(--sky); - text-decoration: underline; - text-underline-offset: 2px; + color: var(--sky); + text-decoration: underline; + text-underline-offset: 2px; } .card-desc a:hover { - color: var(--mauve); + color: var(--mauve); } .card-arrow { - font-size: 0.8rem; - color: var(--overlay0); - transition: color 0.2s, transform 0.2s; - align-self: flex-end; - margin-top: 0.5rem; + font-size: 0.8rem; + color: var(--overlay0); + transition: + color 0.2s, + transform 0.2s; + align-self: flex-end; + margin-top: 0.5rem; } .card:hover .card-arrow { - color: var(--mauve); - transform: translateX(3px); + color: var(--mauve); + transform: translateX(3px); } /* ─── Contact ──────────────────────────────────────────── */ #contact { - min-height: auto; - padding-bottom: 8rem; + min-height: auto; + padding-bottom: 8rem; } .contact-inner { - border: 1px solid var(--surface0); - border-radius: 8px; - padding: 3.5rem; - background: var(--mantle); - display: grid; - grid-template-columns: 1fr 1fr; - gap: 4rem; - align-items: start; + border: 1px solid var(--surface0); + border-radius: 8px; + padding: 3.5rem; + background: var(--mantle); + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4rem; + align-items: start; } .contact-inner h2 { - font-family: 'Fraunces', serif; - font-size: 2.4rem; - font-weight: 600; - color: var(--text); - margin-bottom: 1rem; + font-family: "Fraunces", serif; + font-size: 2.4rem; + font-weight: 600; + color: var(--text); + margin-bottom: 1rem; } .contact-inner h2 em { - font-style: italic; - color: var(--mauve); + font-style: italic; + color: var(--mauve); } .contact-inner p { - color: var(--subtext0); - font-size: 0.88rem; - line-height: 1.8; - margin-bottom: 1.5rem; + color: var(--subtext0); + font-size: 0.88rem; + line-height: 1.8; + margin-bottom: 1.5rem; } .contact-links { - display: flex; - flex-direction: column; - gap: 0.75rem; + display: flex; + flex-direction: column; + gap: 0.75rem; } .contact-link { - display: flex; - align-items: center; - gap: 1rem; - padding: 1rem 1.25rem; - border: 1px solid var(--surface0); - border-radius: 6px; - text-decoration: none; - color: var(--text); - background: var(--base); - transition: all 0.2s; - font-size: 0.85rem; + display: flex; + align-items: center; + gap: 1rem; + padding: 1rem 1.25rem; + border: 1px solid var(--surface0); + border-radius: 6px; + text-decoration: none; + color: var(--text); + background: var(--base); + transition: all 0.2s; + font-size: 0.85rem; } .contact-link:hover { - border-color: var(--mauve); - color: var(--mauve); - transform: translateX(4px); + border-color: var(--mauve); + color: var(--mauve); + transform: translateX(4px); } .contact-link-icon { - width: 1.125rem; - height: 1.125rem; - flex: 0 0 1.125rem; - background: currentColor; - -webkit-mask-repeat: no-repeat; - -webkit-mask-position: center; - -webkit-mask-size: contain; - mask-repeat: no-repeat; - mask-position: center; - mask-size: contain; + width: 1.125rem; + height: 1.125rem; + flex: 0 0 1.125rem; + background: currentColor; + -webkit-mask-repeat: no-repeat; + -webkit-mask-position: center; + -webkit-mask-size: contain; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; } .contact-link-icon--github { - -webkit-mask-image: url('icons/github.svg'); - mask-image: url('icons/github.svg'); + -webkit-mask-image: url("icons/github.svg"); + mask-image: url("icons/github.svg"); } .contact-link-icon--linkedin { - -webkit-mask-image: url('icons/linkedin.svg'); - mask-image: url('icons/linkedin.svg'); + -webkit-mask-image: url("icons/linkedin.svg"); + mask-image: url("icons/linkedin.svg"); } .contact-link-label { - flex: 1; + flex: 1; } .contact-link-handle { - font-size: 0.72rem; - color: var(--overlay1); + font-size: 0.72rem; + color: var(--overlay1); } /* ─── Footer ───────────────────────────────────────────── */ footer { - border-top: 1px solid var(--surface0); - padding: 1.5rem 3rem; - display: flex; - justify-content: space-between; - align-items: center; - font-size: 0.72rem; - color: var(--overlay0); + border-top: 1px solid var(--surface0); + padding: 1.5rem 3rem; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 0.72rem; + color: var(--overlay0); } footer a { - color: var(--overlay1); - text-decoration: none; + color: var(--overlay1); + text-decoration: none; } footer a:hover { - color: var(--mauve); + color: var(--mauve); } /* ─── Animations ───────────────────────────────────────── */ @keyframes fadeUp { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } } .reveal { - opacity: 0; - transform: translateY(24px); - transition: opacity 0.6s ease, transform 0.6s ease; + opacity: 0; + transform: translateY(24px); + transition: + opacity 0.6s ease, + transform 0.6s ease; } .reveal.visible { - opacity: 1; - transform: none; + opacity: 1; + transform: none; } /* ─── Divider ──────────────────────────────────────────── */ .divider { - height: 1px; - background: var(--surface0); - max-width: 1100px; - margin: 0 auto; + height: 1px; + background: var(--surface0); + max-width: 1100px; + margin: 0 auto; } /* ─── Responsive ───────────────────────────────────────── */ @media (max-width: 768px) { - nav { - padding: 0 1.5rem; - } + nav { + padding: 0 1.5rem; + } - .nav-links { - gap: 1.2rem; - } + .nav-links { + gap: 1.2rem; + } - section { - padding: 6rem 1.5rem 4rem; - } + section { + padding: 6rem 1.5rem 4rem; + } - .card-grid.card-grid--featured { - grid-template-columns: 1fr; - } + .card-grid.card-grid--featured { + grid-template-columns: 1fr; + } - #project-grid { - grid-template-columns: 1fr; - } + #project-grid { + grid-template-columns: 1fr; + } - .about-columns { - grid-template-columns: 1fr; - } + .about-columns { + grid-template-columns: 1fr; + } - .about-block-tag { - width: 4rem; - } + .about-block-tag { + width: 4rem; + } - .skills-grid { - grid-template-columns: 1fr; - } + .skills-grid { + grid-template-columns: 1fr; + } - .skill-card--wide { - grid-column: 1; - } + .skill-card--wide { + grid-column: 1; + } - .contact-inner { - grid-template-columns: 1fr; - gap: 2rem; - padding: 2rem; - } + .contact-inner { + grid-template-columns: 1fr; + gap: 2rem; + padding: 2rem; + } - .hero-name { - font-size: clamp(2.8rem, 12vw, 5rem); - } + .hero-name { + font-size: clamp(2.8rem, 12vw, 5rem); + } - .hero-by-line { - align-items: flex-start; - flex-wrap: wrap; - gap: 0.35rem; - margin-bottom: 0.45rem; - } + .hero-by-line { + align-items: flex-start; + flex-wrap: wrap; + gap: 0.35rem; + margin-bottom: 0.45rem; + } - .hero-by-line:last-child { - margin-bottom: 0; - } + .hero-by-line:last-child { + margin-bottom: 0; + } - .hero-by { - font-size: 0.86rem; - line-height: 1.5; - } + .hero-by { + font-size: 0.86rem; + line-height: 1.5; + } - .hero-by-role { - font-size: 0.8rem; - line-height: 1.5; - opacity: 0.75; - } + .hero-by-role { + font-size: 0.8rem; + line-height: 1.5; + opacity: 0.75; + } - footer { - flex-direction: column; - gap: 0.5rem; - text-align: center; - } + footer { + flex-direction: column; + gap: 0.5rem; + text-align: center; + } } diff --git a/tutorials/convex_hull/index.html b/tutorials/convex_hull/index.html index 2f5dbe8..8790f93 100644 --- a/tutorials/convex_hull/index.html +++ b/tutorials/convex_hull/index.html @@ -1,4 +1,4 @@ - + Convex Hull diff --git a/tutorials/convex_hull/style.css b/tutorials/convex_hull/style.css index b9ecafb..69ced17 100644 --- a/tutorials/convex_hull/style.css +++ b/tutorials/convex_hull/style.css @@ -1,56 +1,55 @@ -h1{ - font-family: 'Roboto Condensed', sans-serif; - margin: 0; - padding: 0 0 15px 0; - font-weight: 700; - font-size: 32px; +h1 { + font-family: "Roboto Condensed", sans-serif; + margin: 0; + padding: 0 0 15px 0; + font-weight: 700; + font-size: 32px; } -h2{ - font-family: 'Roboto Condensed', sans-serif; - margin: 0; - padding: 15px 0 15px 0; - font-weight: 650; - font-size: 20px; +h2 { + font-family: "Roboto Condensed", sans-serif; + margin: 0; + padding: 15px 0 15px 0; + font-weight: 650; + font-size: 20px; } -p{ - margin: 1px; - font-family: 'Roboto', sans-serif; - font-size: 19px; - padding: 5px 0px 5px 0px; +p { + margin: 1px; + font-family: "Roboto", sans-serif; + font-size: 19px; + padding: 5px 0px 5px 0px; } -.psudoCode{ - font-family: 'Inconsolata', monospace; - font-size: 19px; - background-color: #D9D9D9; - border: 1px solid; - padding: 5px; - box-shadow: 5px 5px #888888; +.psudoCode { + font-family: "Inconsolata", monospace; + font-size: 19px; + background-color: #d9d9d9; + border: 1px solid; + padding: 5px; + box-shadow: 5px 5px #888888; } -a{ - font-family: 'Inconsolata', monospace; - font-size: 19px; - background-color: #D9D9D9; - +a { + font-family: "Inconsolata", monospace; + font-size: 19px; + background-color: #d9d9d9; } -button{ - background-color: white; - border: 2px solid #555555; - color: black; - padding: 16px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - -webkit-transition-duration: 0.4s; /* Safari */ - transition-duration: 0.4s; - cursor: pointer; - float:right; +button { + background-color: white; + border: 2px solid #555555; + color: black; + padding: 16px 32px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: 4px 2px; + -webkit-transition-duration: 0.4s; /* Safari */ + transition-duration: 0.4s; + cursor: pointer; + float: right; } button:hover { @@ -58,14 +57,13 @@ button:hover { color: white; } -.examples{ - padding: 10px; +.examples { + padding: 10px; } - -html{ - -webkit-user-select: none; /* Safari */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE10+/Edge */ - user-select: none; /* Standard */ +html { + -webkit-user-select: none; /* Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+/Edge */ + user-select: none; /* Standard */ } diff --git a/tutorials/midpoint_displacement/style.css b/tutorials/midpoint_displacement/style.css index b9ecafb..69ced17 100644 --- a/tutorials/midpoint_displacement/style.css +++ b/tutorials/midpoint_displacement/style.css @@ -1,56 +1,55 @@ -h1{ - font-family: 'Roboto Condensed', sans-serif; - margin: 0; - padding: 0 0 15px 0; - font-weight: 700; - font-size: 32px; +h1 { + font-family: "Roboto Condensed", sans-serif; + margin: 0; + padding: 0 0 15px 0; + font-weight: 700; + font-size: 32px; } -h2{ - font-family: 'Roboto Condensed', sans-serif; - margin: 0; - padding: 15px 0 15px 0; - font-weight: 650; - font-size: 20px; +h2 { + font-family: "Roboto Condensed", sans-serif; + margin: 0; + padding: 15px 0 15px 0; + font-weight: 650; + font-size: 20px; } -p{ - margin: 1px; - font-family: 'Roboto', sans-serif; - font-size: 19px; - padding: 5px 0px 5px 0px; +p { + margin: 1px; + font-family: "Roboto", sans-serif; + font-size: 19px; + padding: 5px 0px 5px 0px; } -.psudoCode{ - font-family: 'Inconsolata', monospace; - font-size: 19px; - background-color: #D9D9D9; - border: 1px solid; - padding: 5px; - box-shadow: 5px 5px #888888; +.psudoCode { + font-family: "Inconsolata", monospace; + font-size: 19px; + background-color: #d9d9d9; + border: 1px solid; + padding: 5px; + box-shadow: 5px 5px #888888; } -a{ - font-family: 'Inconsolata', monospace; - font-size: 19px; - background-color: #D9D9D9; - +a { + font-family: "Inconsolata", monospace; + font-size: 19px; + background-color: #d9d9d9; } -button{ - background-color: white; - border: 2px solid #555555; - color: black; - padding: 16px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - -webkit-transition-duration: 0.4s; /* Safari */ - transition-duration: 0.4s; - cursor: pointer; - float:right; +button { + background-color: white; + border: 2px solid #555555; + color: black; + padding: 16px 32px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: 4px 2px; + -webkit-transition-duration: 0.4s; /* Safari */ + transition-duration: 0.4s; + cursor: pointer; + float: right; } button:hover { @@ -58,14 +57,13 @@ button:hover { color: white; } -.examples{ - padding: 10px; +.examples { + padding: 10px; } - -html{ - -webkit-user-select: none; /* Safari */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE10+/Edge */ - user-select: none; /* Standard */ +html { + -webkit-user-select: none; /* Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+/Edge */ + user-select: none; /* Standard */ } diff --git a/tutorials/summed_area/index.html b/tutorials/summed_area/index.html index d11731f..f70cbf3 100644 --- a/tutorials/summed_area/index.html +++ b/tutorials/summed_area/index.html @@ -1,43 +1,49 @@ - + - - - - + + + - - + + + .then((r) => r.text()) + .then((code) => { + document.getElementById("count-squares").textContent = code; + if (window.hljs) + hljs.highlightElement(document.getElementById("count-squares")); + }); + - +

Summed-area Table

- 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 - processing it is also known as an integral image. + 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 + processing it is also known as an integral image.

- + - +

- 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 - 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). + 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 + 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).

         
@@ -45,10 +51,10 @@
     

- 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 - by interrogating 4 cells and performing only 4 additions. NOTE: we have to - add the 'top left' region as it as been subtracted twice. + 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 + by interrogating 4 cells and performing only 4 additions. NOTE: we have to + add the 'top left' region as it as been subtracted twice.

@@ -59,28 +65,26 @@
     

Click a sqaure on the grid to turn it on or off.

Shift+Click two square to define a rectangle.

- Press the show count button to display the sum value of each cell - (in this example a cell's value can only be 0 or 1). + Press the show count button to display the sum value of each cell + (in this example a cell's value can only be 0 or 1).

- Press show rectangles to see the different regions simplified and - see how - it changes the sum below. + Press show rectangles to see the different regions simplified and + see how it changes the sum below.

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

Travelling Sales Person Problem

- + Travelling Sales Person +

Travelling Sales Person Problem

+ - - + +
- TSP Problem - + TSP Problem
-

The travelling salesman problem (TSP) asks the following question: "Given a list of cities and the distances - between each pair of cities, what is the shortest possible route that visits each city and returns to the origin - city?"

-

The problem was first formulated in 1930 and is one of the most intensively studied problems in optimization. It - is used as a benchmark for many optimization methods. Even though the problem is computationally difficult, a - large number of heuristics and exact algorithms are known, so that some instances with tens of thousands of - cities can be solved completely and even problems with millions of cities can be approximated within a small - fraction of 1%.

-

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.

+

+ The travelling salesman problem (TSP) asks the following question: "Given + a list of cities and the distances between each pair of cities, what is + the shortest possible route that visits each city and returns to the + origin city?" +

+

+ The problem was first formulated in 1930 and is one of the most + intensively studied problems in optimization. It is used as a benchmark + for many optimization methods. Even though the problem is computationally + difficult, a large number of heuristics and exact algorithms are known, so + that some instances with tens of thousands of cities can be solved + completely and even problems with millions of cities can be approximated + within a small fraction of 1%. +

+

+ 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. +

These are some of the algorithms I used

-

Note the purple route is the best route it's found so far and the thin white lines are the routes it's trying - real time.

- +

+ Note the purple route is the best route it's found so far and the thin + white lines are the routes it's trying real time. +

+ - +
-

Random Sort

- -

This canvas sorts through random possiblities. Every frame the program chooses two random - points (cities) and swaps them around. eg say the order was London, Paris, Madrid, the program would swap - London and Paris so that the new order is: Paris, London, Madrid. The program then compares the distance - against the record distance to decide whether the new order is better than the old order. This search method - is the most inefficient way, the worst case scenario is never ending, as the point swaping is random the - program may never reach the optimum route


-

Lexicographic Order

- -

This canvas sorts through all possible orders sequentially, so after n! (where n is the - number of points) this algorithm is guaranteed to have found the quickest possible route. However it is - highly inefficient always taking n! frames to complete and as n increases, time taken increases - exponentially.

- Click - here to learn more about the algorithm
-

Genetic Algorithm

- -

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.


+

Random Sort

+ +

+ This canvas sorts through random possiblities. Every frame the program + chooses two random points (cities) and swaps them around. eg say the + order was London, Paris, Madrid, the program would swap London and Paris + so that the new order is: Paris, London, Madrid. The program then + compares the distance against the record distance to decide whether the + new order is better than the old order. This search method is the most + inefficient way, the worst case scenario is never ending, as the point + swaping is random the program may never reach the optimum route +

+
+

Lexicographic Order

+ +

+ This canvas sorts through all possible orders sequentially, so after n! + (where n is the number of points) this algorithm is guaranteed to have + found the quickest possible route. However it is highly inefficient + always taking n! frames to complete and as n increases, time taken + increases exponentially. +

+ Click here to learn more about the algorithm
+

Genetic Algorithm

+ +

+ 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. +

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