formatting

This commit is contained in:
John Gatward
2026-03-20 18:46:38 +00:00
parent ed713a931d
commit af0cb702a2
3 changed files with 1099 additions and 946 deletions

View File

@@ -2,465 +2,467 @@
<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>Havox — John Gatward</title> <title>Havox — John Gatward</title>
<meta name="description" content="John Gatward's portfolio: software engineering projects spanning backend systems, infrastructure, and creative developer experiments." /> <meta name="description"
content="John Gatward's portfolio: software engineering projects spanning backend systems, infrastructure, and creative developer experiments."/>
<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="style.css"/>
</head> </head>
<body> <body>
<!-- ─── Nav ─────────────────────────────────────────────────── --> <!-- ─── Nav ─────────────────────────────────────────────────── -->
<nav> <nav>
<a href="#hero" class="nav-logo">havox</a> <a href="#hero" class="nav-logo">havox</a>
<ul class="nav-links"> <ul class="nav-links">
<li><a href="#about">about</a></li> <li><a href="#about">about</a></li>
<li><a href="#skills">skills</a></li> <li><a href="#skills">skills</a></li>
<li><a href="#projects">projects</a></li> <li><a href="#projects">projects</a></li>
<li><a href="#contact">contact</a></li> <li><a href="#contact">contact</a></li>
</ul> </ul>
</nav> </nav>
<!-- ─── Hero ─────────────────────────────────────────────────── --> <!-- ─── Hero ─────────────────────────────────────────────────── -->
<section id="hero"> <section id="hero">
<p class="hero-eyebrow">// havox.org — v4</p> <p class="hero-eyebrow">// havox.org — v4</p>
<h1 class="hero-name">John <em>Gatward</em></h1> <h1 class="hero-name">John <em>Gatward</em></h1>
<p class="hero-subtitle">Software Engineer</p> <p class="hero-subtitle">Software Engineer</p>
<p class="hero-desc"> <p class="hero-desc">
<span class="hero-by-line"><span class="hero-by">Backend engineer</span><span class="hero-by-role">by <span class="hero-by-line"><span class="hero-by">Backend engineer</span><span class="hero-by-role">by
trade</span></span> trade</span></span>
<span class="hero-by-line"><span class="hero-by">Developer enthusiast</span><span class="hero-by-role">by <span class="hero-by-line"><span class="hero-by">Developer enthusiast</span><span class="hero-by-role">by
curiosity</span></span> curiosity</span></span>
<span class="hero-by-line"><span class="hero-by">Unofficial family cloud engineer</span><span <span class="hero-by-line"><span class="hero-by">Unofficial family cloud engineer</span><span
class="hero-by-role">by necessity</span></span> class="hero-by-role">by necessity</span></span>
<span class="hero-by-footer">I like building useful things and understanding how they work.</span> <span class="hero-by-footer">I like building useful things and understanding how they work.</span>
</p> </p>
<div class="hero-links"> <div class="hero-links">
<a href="#projects" class="btn btn-primary">View projects</a> <a href="#projects" class="btn btn-primary">View projects</a>
<a href="#contact" class="btn btn-ghost">Contact me</a> <a href="#contact" class="btn btn-ghost">Contact me</a>
</div> </div>
</section> </section>
<div class="divider"></div> <div class="divider"></div>
<!-- ─── About ─────────────────────────────────────────────────── --> <!-- ─── About ─────────────────────────────────────────────────── -->
<section id="about" class="about-section"> <section id="about" class="about-section">
<div class="reveal"> <div class="reveal">
<p class="section-label">about</p> <p class="section-label">about</p>
<h2 class="section-heading">Havox & <em>me</em></h2> <h2 class="section-heading">Havox & <em>me</em></h2>
</div> </div>
<div class="about-columns"> <div class="about-columns">
<!-- Bio blocks --> <!-- Bio blocks -->
<div class="about-grid reveal" style="transition-delay:0.05s"> <div class="about-grid reveal" style="transition-delay:0.05s">
<div class="about-block">
<span class="about-block-tag tag tag-blue">day job</span>
<p>Backend engineer at <strong>Sainsbury's</strong> Supply Chain &amp; Logistics. Microservices,
Spring Boot, Kafka, MongoDB, AWS. It's good fun.</p>
</div>
<div class="about-block">
<span class="about-block-tag tag tag-teal">dev</span>
<p>Fascinated with new languages, frameworks, and shiny tech I probably dont need. Constantly
tinkering, breaking things, and learning just enough to build something cooler next time.</p>
</div>
<div class="about-block">
<span class="about-block-tag tag tag-yellow">linux</span>
<p>Long-time Linux user and recovering distro-hopper. Currently: Hyprland on Void. Home server
running 24/7 for friends and family who didn't ask for it but appreciate it.</p>
</div>
<div class="about-block">
<span class="about-block-tag tag tag-mauve">havox</span>
<p>Started in 2017 as a place to dump whatever I found interesting. Four redesigns and several dead
domains later, it's still going. Less a portfolio, more a paper trail.</p>
</div>
<div class="about-block">
<span class="about-block-tag tag tag-blue">day job</span>
<p>Backend engineer at <strong>Sainsbury's</strong> Supply Chain &amp; Logistics. Microservices,
Spring Boot, Kafka, MongoDB, AWS. It's good fun.</p>
</div> </div>
<!-- Version timeline --> <div class="about-block">
<div class="reveal" style="transition-delay:0.15s"> <span class="about-block-tag tag tag-teal">dev</span>
<p class="section-label">version history</p> <p>Fascinated with new languages, frameworks, and shiny tech I probably dont need. Constantly
<div class="version-timeline"> tinkering, breaking things, and learning just enough to build something cooler next time.</p>
</div>
<div class="version-item"> <div class="about-block">
<div class="v-dot v-dot--current"></div> <span class="about-block-tag tag tag-yellow">linux</span>
<div class="v-content"> <p>Long-time Linux user and recovering distro-hopper. Currently: Hyprland on Void. Home server
<div class="v-title">Havox V4 <span class="v-current-badge">current</span></div> running 24/7 for friends and family who didn't ask for it but appreciate it.</p>
<div class="v-year">2026 → present</div> </div>
<div class="v-desc">Catppuccin Mocha. Single page. Built to highlight projects and craft.</div>
<div class="about-block">
<span class="about-block-tag tag tag-mauve">havox</span>
<p>Started in 2017 as a place to dump whatever I found interesting. Four redesigns and several dead
domains later, it's still going. Less a portfolio, more a paper trail.</p>
</div>
</div>
<!-- Version timeline -->
<div class="reveal" style="transition-delay:0.15s">
<p class="section-label">version history</p>
<div class="version-timeline">
<div class="version-item">
<div class="v-dot v-dot--current"></div>
<div class="v-content">
<div class="v-title">Havox V4 <span class="v-current-badge">current</span></div>
<div class="v-year">2026 → present</div>
<div class="v-desc">Catppuccin Mocha. Single page. Built to highlight projects and craft.</div>
</div>
</div>
<a class="version-item version-item--link" href="archive/v3/index.html">
<div class="v-dot"></div>
<div class="v-content">
<div class="v-title">Havox V3 <span class="v-link-arrow"></span></div>
<div class="v-year">2022 → 2025</div>
<div class="v-desc">Borrowed a professional looking template. Wasn't very 'me'.</div>
</div>
</a>
<a class="version-item version-item--link" href="archive/v2/index.html">
<div class="v-dot"></div>
<div class="v-content">
<div class="v-title">Umbra.cyou <span class="v-link-arrow"></span></div>
<div class="v-year">2019 → 2022</div>
<div class="v-desc">Complete redesign using SCSS & Nord theme.</div>
</div>
</a>
<a class="version-item version-item--link" href="archive/v1/index.html">
<div class="v-dot"></div>
<div class="v-content">
<div class="v-title">Havox.org <span class="v-link-arrow"></span></div>
<div class="v-year">2016 → 2019</div>
<div class="v-desc">Entire site in one PHP file 🤣. Had a daily <s>trump</s>
quote-of-the-day achieved via webscraping a site daily.
</div> </div>
</div> </div>
</a>
<a class="version-item version-item--link" href="archive/v3/index.html">
<div class="v-dot"></div>
<div class="v-content">
<div class="v-title">Havox V3 <span class="v-link-arrow"></span></div>
<div class="v-year">2022 → 2025</div>
<div class="v-desc">Borrowed a professional looking template. Wasn't very 'me'.</div>
</div>
</a>
<a class="version-item version-item--link" href="archive/v2/index.html">
<div class="v-dot"></div>
<div class="v-content">
<div class="v-title">Umbra.cyou <span class="v-link-arrow"></span></div>
<div class="v-year">2019 → 2022</div>
<div class="v-desc">Complete redesign using SCSS & Nord theme.</div>
</div>
</a>
<a class="version-item version-item--link" href="archive/v1/index.html">
<div class="v-dot"></div>
<div class="v-content">
<div class="v-title">Havox.org <span class="v-link-arrow"></span></div>
<div class="v-year">2016 → 2019</div>
<div class="v-desc">Entire site in one PHP file 🤣. Had a daily <s>trump</s>
quote-of-the-day achieved via webscraping a site daily.</div>
</div>
</a>
</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ─── Skills ─────────────────────────────────────────────────── -->
<section id="skills">
<p class="section-label reveal">skills</p>
<h2 class="section-heading reveal" style="transition-delay:0.05s">What I <em>know</em></h2>
<div class="skills-grid">
<div class="skill-card reveal">
<span class="skill-card-icon"></span>
<h3>Backend</h3>
<p>Professional Java experience building microservices &amp; RESTful APIs with Spring Boot. TDD with
JUnit & Mockito.</p>
<div class="tag-row">
<span class="tag tag-blue">Java</span>
<span class="tag tag-green">Spring Boot</span>
<span class="tag tag-teal">AWS</span>
<span class="tag tag-peach">Kafka</span>
<span class="tag tag-sky">MongoDB</span>
</div>
</div>
<div class="skill-card reveal" style="transition-delay:0.08s">
<span class="skill-card-icon">🎨</span>
<h3>Frontend & Creative</h3>
<p>Comfortable with react and CSS. I enjoy visualising algorithms interactively — it's more fun than
a console output.</p>
<div class="tag-row">
<span class="tag tag-teal">React</span>
<span class="tag tag-green">TypeScript</span>
<span class="tag tag-blue">HTML/CSS</span>
</div>
</div>
<div class="skill-card reveal" style="transition-delay:0.16s">
<span class="skill-card-icon">🖥</span>
<h3>Systems & Infra</h3>
<p>Long-term Linux user. Self-hosted web & media servers. Comfortable with networking, security
practices, and the command line.</p>
<div class="tag-row">
<span class="tag tag-green">Linux</span>
<span class="tag tag-teal">Docker</span>
<span class="tag tag-blue">Self-Hosting</span>
<span class="tag tag-peach">Wireguard</span>
</div>
</div>
<div class="skill-card skill-card--wide reveal" style="transition-delay:0.24s">
<span class="skill-card-icon">🎓</span>
<h3>Academic Breadth</h3>
<p>C, C++, x86_64 assembly, Haskell, R &amp; MatLab from uni. Modules in Advanced networking,
algorithms, compilers,
graphics, cryptography, malware analysis & many more.</p>
<div class="tag-row">
<span class="tag tag-blue">C / C++</span>
<span class="tag tag-mauve">Haskell</span>
<span class="tag tag-yellow">Algorithms</span>
<span class="tag tag-teal">Security</span>
<span class="tag tag-peach">Low Level OS</span>
</div>
</div> </div>
</div> </div>
</section>
<div class="divider"></div> </div>
<!-- ─── Projects ──────────────────────────────────────────────── --> </section>
<section id="projects">
<p class="section-label reveal">projects</p>
<h2 class="section-heading reveal" style="transition-delay:0.05s">Things I <em>built</em></h2>
<p class="section-intro reveal" style="transition-delay:0.1s">
A timeline of projects focused on technical challenge and what each build taught me.
</p>
<div class="projects-subheading reveal" style="transition-delay:0.12s"> <div class="divider"></div>
<span>Featured projects</span>
<!-- ─── Skills ─────────────────────────────────────────────────── -->
<section id="skills">
<p class="section-label reveal">skills</p>
<h2 class="section-heading reveal" style="transition-delay:0.05s">What I <em>know</em></h2>
<div class="skills-grid">
<div class="skill-card reveal">
<span class="skill-card-icon"></span>
<h3>Backend</h3>
<p>Professional Java experience building microservices &amp; RESTful APIs with Spring Boot. TDD with
JUnit & Mockito.</p>
<div class="tag-row">
<span class="tag tag-blue">Java</span>
<span class="tag tag-green">Spring Boot</span>
<span class="tag tag-teal">AWS</span>
<span class="tag tag-peach">Kafka</span>
<span class="tag tag-sky">MongoDB</span>
</div>
</div> </div>
<div class="skill-card reveal" style="transition-delay:0.08s">
<span class="skill-card-icon">🎨</span>
<h3>Frontend & Creative</h3>
<p>Comfortable with react and CSS. I enjoy visualising algorithms interactively — it's more fun than
a console output.</p>
<div class="tag-row">
<span class="tag tag-teal">React</span>
<span class="tag tag-green">TypeScript</span>
<span class="tag tag-blue">HTML/CSS</span>
</div>
</div>
<div class="skill-card reveal" style="transition-delay:0.16s">
<span class="skill-card-icon">🖥</span>
<h3>Systems & Infra</h3>
<p>Long-term Linux user. Self-hosted web & media servers. Comfortable with networking, security
practices, and the command line.</p>
<div class="tag-row">
<span class="tag tag-green">Linux</span>
<span class="tag tag-teal">Docker</span>
<span class="tag tag-blue">Self-Hosting</span>
<span class="tag tag-peach">Wireguard</span>
</div>
</div>
<div class="skill-card skill-card--wide reveal" style="transition-delay:0.24s">
<span class="skill-card-icon">🎓</span>
<h3>Academic Breadth</h3>
<p>C, C++, x86_64 assembly, Haskell, R &amp; MatLab from uni. Modules in Advanced networking,
algorithms, compilers,
graphics, cryptography, malware analysis & many more.</p>
<div class="tag-row">
<span class="tag tag-blue">C / C++</span>
<span class="tag tag-mauve">Haskell</span>
<span class="tag tag-yellow">Algorithms</span>
<span class="tag tag-teal">Security</span>
<span class="tag tag-peach">Low Level OS</span>
</div>
</div>
</div>
</section>
<div class="card-grid card-grid--featured reveal" style="transition-delay:0.14s"> <div class="divider"></div>
<a class="card" href="https://wordlesolver.umbra.mom">
<span class="card-date">9 Jan 2025</span> <!-- ─── Projects ──────────────────────────────────────────────── -->
<span class="card-title">Wordle Solver</span> <section id="projects">
<span class="card-desc">Built after getting frustrated after one too many missed 3-guess games. Now it <p class="section-label reveal">projects</p>
<h2 class="section-heading reveal" style="transition-delay:0.05s">Things I <em>built</em></h2>
<p class="section-intro reveal" style="transition-delay:0.1s">
A timeline of fun projects used as an excuse to learn something new.
</p>
<div class="projects-subheading reveal" style="transition-delay:0.12s">
<span>Featured projects</span>
</div>
<div class="card-grid card-grid--featured reveal" style="transition-delay:0.14s">
<a class="card" href="https://wordlesolver.umbra.mom">
<span class="card-date">9 Feb 2025</span>
<span class="card-title">Wordle Solver</span>
<span class="card-desc">Built after getting frustrated after one too many missed 3-guess games. Now it
plays marginally better than me. Uses information theory to recommend the next best guess.</span> plays marginally better than me. Uses information theory to recommend the next best guess.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-yellow">Rust</span> <span class="tag tag-yellow">Rust</span>
<span class="tag tag-teal">React</span> <span class="tag tag-teal">React</span>
<span class="tag tag-peach">TypeScript</span> <span class="tag tag-peach">TypeScript</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card" href="#projects"> <a class="card" href="https://crackthequote.umbra.mom">
<span class="card-date">13 Apr 2024</span> <span class="card-date">13 Apr 2024</span>
<span class="card-title">Crack the Quote</span> <span class="card-title">Crack the Quote</span>
<span class="card-desc">A substitution-cipher puzzle game with a daily challenge.</span> <span class="card-desc">A substitution-cipher puzzle game with a daily challenge.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-yellow">Rust</span> <span class="tag tag-yellow">Rust</span>
<span class="tag tag-teal">React</span> <span class="tag tag-teal">React</span>
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
</div> </div>
<div class="projects-subheading reveal" style="transition-delay:0.16s"> <div class="projects-subheading reveal" style="transition-delay:0.16s">
<span>All projects</span> <span>All projects</span>
</div> </div>
<fieldset class="project-filters reveal" style="transition-delay:0.18s" aria-label="Filter projects by tech stack"> <fieldset class="project-filters reveal" style="transition-delay:0.18s" aria-label="Filter projects by tech stack">
<button type="button" class="filter-chip active" data-filter="all">All</button> <button type="button" class="filter-chip active" data-filter="all">All</button>
<button type="button" class="filter-chip" data-filter="javascript">JavaScript</button> <button type="button" class="filter-chip" data-filter="javascript">JavaScript</button>
<button type="button" class="filter-chip" data-filter="python">Python</button> <button type="button" class="filter-chip" data-filter="python">Python</button>
<button type="button" class="filter-chip" data-filter="rust">Rust</button> <button type="button" class="filter-chip" data-filter="rust">Rust</button>
<button type="button" class="filter-chip" data-filter="react">React</button> <button type="button" class="filter-chip" data-filter="react">React</button>
<button type="button" class="filter-chip" data-filter="webassembly">WebAssembly</button> <button type="button" class="filter-chip" data-filter="webassembly">WebAssembly</button>
<button type="button" class="filter-chip" data-filter="p5">p5.js</button> <button type="button" class="filter-chip" data-filter="p5">p5.js</button>
<button type="button" class="filter-chip" data-filter="zig">Zig</button> <button type="button" class="filter-chip" data-filter="zig">Zig</button>
<button type="button" class="filter-chip" data-filter="cpp">C / C++</button> <button type="button" class="filter-chip" data-filter="cpp">C / C++</button>
</fieldset> </fieldset>
<div id="project-grid" class="card-grid reveal" style="transition-delay:0.2s"> <div id="project-grid" class="card-grid reveal" style="transition-delay:0.2s">
<a class="card project-card" data-tech="python" href="https://pubquiz.umbra.mom"> <a class="card project-card" data-tech="python" href="https://pubquiz.umbra.mom">
<span class="card-date">03 Apr 2025</span> <span class="card-date">03 Apr 2025</span>
<span class="card-title">Pub Quiz Dashboard</span> <span class="card-title">Pub Quiz Dashboard</span>
<span class="card-desc">A Python dashboard to track quiz performance.</span> <span class="card-desc">A Python dashboard to track quiz performance.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-red">Python</span> <span class="tag tag-red">Python</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="cpp webassembly" href="projects/thin_ice/thin_ice.html"> <a class="card project-card" data-tech="cpp webassembly" href="projects/thin_ice/thin_ice.html">
<span class="card-date">14 Nov 2024</span> <span class="card-date">14 Nov 2024</span>
<span class="card-title">Thin Ice</span> <span class="card-title">Thin Ice</span>
<span class="card-desc">A small browser tile game inspired by one I played growing up.</span> <span class="card-desc">A small browser tile game inspired by one I played growing up.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-blue">C++</span> <span class="tag tag-blue">C++</span>
<span class="tag tag-teal">WebAssembly</span> <span class="tag tag-teal">WebAssembly</span>
<span class="tag tag-peach">RayLib</span> <span class="tag tag-peach">RayLib</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="zig webassembly" href="projects/tsp/index.html"> <a class="card project-card" data-tech="zig webassembly" href="projects/tsp/index.html">
<span class="card-date">20 Mar 2024</span> <span class="card-date">20 Mar 2024</span>
<span class="card-title">Travelling Salesman Problem</span> <span class="card-title">Travelling Salesman Problem</span>
<span class="card-desc">A nearest-neighbor + 2-opt visualiser.</span> <span class="card-desc">A nearest-neighbor + 2-opt visualiser.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-yellow">Zig</span> <span class="tag tag-yellow">Zig</span>
<span class="tag tag-sky">WebGL</span> <span class="tag tag-sky">WebGL</span>
<span class="tag tag-teal">WebAssembly</span> <span class="tag tag-teal">WebAssembly</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="rust" href="projects/flocking/index.html"> <a class="card project-card" data-tech="rust" href="projects/flocking/index.html">
<span class="card-date">31 Jan 2024</span> <span class="card-date">31 Jan 2024</span>
<span class="card-title">Flocking</span> <span class="card-title">Flocking</span>
<span class="card-desc">A boids simulation showing emergent behaviour from three simple rules.</span> <span class="card-desc">A boids simulation showing emergent behaviour from three simple rules.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-yellow">Rust</span> <span class="tag tag-yellow">Rust</span>
<span class="tag tag-peach">Raylib</span> <span class="tag tag-peach">Raylib</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="javascript" href="https://samstoreymusic.com"> <a class="card project-card" data-tech="javascript" href="https://samstoreymusic.com">
<span class="card-date">1 Nov 2023</span> <span class="card-date">1 Nov 2023</span>
<span class="card-title">samstoreymusic.com</span> <span class="card-title">samstoreymusic.com</span>
<span class="card-desc">A website design and build for a friend working in music.</span> <span class="card-desc">A website design and build for a friend working in music.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-mauve">HTML/CSS</span> <span class="tag tag-mauve">HTML/CSS</span>
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="javascript react" href="projects/cellular_automata/index.html"> <a class="card project-card" data-tech="javascript react" href="projects/cellular_automata/index.html">
<span class="card-date">21 Jul 2023</span> <span class="card-date">21 Jul 2023</span>
<span class="card-title">Game of Life</span> <span class="card-title">Game of Life</span>
<span class="card-desc">After building Conway's Game of Life in p5.js, I expanded it into a generic automata simulator.</span> <span class="card-desc">After building Conway's Game of Life in p5.js, I expanded it into a generic automata simulator.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-teal">React</span> <span class="tag tag-teal">React</span>
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="cpp webassembly" href="projects/percolation/index.html"> <a class="card project-card" data-tech="cpp webassembly" href="projects/percolation/index.html">
<span class="card-date">5 Feb 2022</span> <span class="card-date">5 Feb 2022</span>
<span class="card-title">Percolation</span> <span class="card-title">Percolation</span>
<span class="card-desc">A visual demo of 'water' percolating through a medium, as it disappears.</span> <span class="card-desc">A visual demo of 'water' percolating through a medium, as it disappears.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-blue">C</span> <span class="tag tag-blue">C</span>
<span class="tag tag-peach">RayLib</span> <span class="tag tag-peach">RayLib</span>
<span class="tag tag-teal">WebAssembly</span> <span class="tag tag-teal">WebAssembly</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="javascript p5" href="projects/cubic_bezier_curve/index.html"> <a class="card project-card" data-tech="javascript p5" href="projects/cubic_bezier_curve/index.html">
<span class="card-date">1 Oct 2021</span> <span class="card-date">1 Oct 2021</span>
<span class="card-title">Drawing Bézier curves</span> <span class="card-title">Drawing Bézier curves</span>
<span class="card-desc">An interactive diagram for cubic Bézier curves.</span> <span class="card-desc">An interactive diagram for cubic Bézier curves.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
<span class="tag tag-red">p5.js</span> <span class="tag tag-red">p5.js</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="javascript p5" href="projects/marching_squares.html"> <a class="card project-card" data-tech="javascript p5" href="projects/marching_squares.html">
<span class="card-date">17 Sep 2021</span> <span class="card-date">17 Sep 2021</span>
<span class="card-title">2D Marching Squares</span> <span class="card-title">2D Marching Squares</span>
<span class="card-desc">Basic map rendering.</span> <span class="card-desc">Basic map rendering.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
<span class="tag tag-red">p5.js</span> <span class="tag tag-red">p5.js</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="javascript p5" href="projects/warping_lines.html"> <a class="card project-card" data-tech="javascript p5" href="projects/warping_lines.html">
<span class="card-date">2 Apr 2020</span> <span class="card-date">2 Apr 2020</span>
<span class="card-title">Müller-Lyer illusion</span> <span class="card-title">Müller-Lyer illusion</span>
<span class="card-desc">A JavaScript visualisation of the Müller-Lyer optical illusion.</span> <span class="card-desc">A JavaScript visualisation of the Müller-Lyer optical illusion.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
<span class="tag tag-red">p5.js</span> <span class="tag tag-red">p5.js</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="javascript p5" href="projects/fourier_series.html"> <a class="card project-card" data-tech="javascript p5" href="projects/fourier_series.html">
<span class="card-date">27 Feb 2019</span> <span class="card-date">27 Feb 2019</span>
<span class="card-title">Fourier series</span> <span class="card-title">Fourier series</span>
<span class="card-desc">Builds a square wave from sine components to show Fourier series in motion.</span> <span class="card-desc">Builds a square wave from sine components to show Fourier series in motion.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
<span class="tag tag-red">p5.js</span> <span class="tag tag-red">p5.js</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="javascript p5" href="projects/ellipse_construction.html"> <a class="card project-card" data-tech="javascript p5" href="projects/ellipse_construction.html">
<span class="card-date">23 Feb 2019</span> <span class="card-date">23 Feb 2019</span>
<span class="card-title">Constructing an ellipse</span> <span class="card-title">Constructing an ellipse</span>
<span class="card-desc">A geometric construction demo inspired by 3Blue1Brown.</span> <span class="card-desc">A geometric construction demo inspired by 3Blue1Brown.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
<span class="tag tag-red">p5.js</span> <span class="tag tag-red">p5.js</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="javascript p5" href="projects/pi_approximation.html"> <a class="card project-card" data-tech="javascript p5" href="projects/pi_approximation.html">
<span class="card-date">18 Mar 2018</span> <span class="card-date">18 Mar 2018</span>
<span class="card-title">Calculating PI</span> <span class="card-title">Calculating PI</span>
<span class="card-desc">A Monte Carlo approximation of pi using random sampling.</span> <span class="card-desc">A Monte Carlo approximation of pi using random sampling.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
<span class="tag tag-red">p5.js</span> <span class="tag tag-red">p5.js</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="javascript p5" href="projects/oscillations_in_3d.html"> <a class="card project-card" data-tech="javascript p5" href="projects/oscillations_in_3d.html">
<span class="card-date">17 Dec 2017</span> <span class="card-date">17 Dec 2017</span>
<span class="card-title">Oscillations in 3D</span> <span class="card-title">Oscillations in 3D</span>
<span class="card-desc">A JavaScript recreation of a Bees and Bombs animation.</span> <span class="card-desc">A JavaScript recreation of a Bees and Bombs animation.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
<span class="tag tag-red">p5.js</span> <span class="tag tag-red">p5.js</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
<a class="card project-card" data-tech="javascript p5" href="projects/maze_generation/index.html"> <a class="card project-card" data-tech="javascript p5" href="projects/maze_generation/index.html">
<span class="card-date">13 Nov 2017</span> <span class="card-date">13 Nov 2017</span>
<span class="card-title">Maze generator</span> <span class="card-title">Maze generator</span>
<span class="card-desc">A p5.js maze generator using depth-first search and recursive backtracking.</span> <span class="card-desc">A p5.js maze generator using depth-first search and recursive backtracking.</span>
<span class="tag-row"> <span class="tag-row">
<span class="tag tag-green">JavaScript</span> <span class="tag tag-green">JavaScript</span>
<span class="tag tag-red">p5.js</span> <span class="tag tag-red">p5.js</span>
</span> </span>
<span class="card-arrow"></span> <span class="card-arrow"></span>
</a> </a>
</div>
<div class="projects-more-row reveal" style="transition-delay:0.22s">
<button id="projects-see-more" type="button" class="projects-more-btn" aria-expanded="false">See more</button>
</div>
</section>
<div class="divider"></div>
<!-- ─── Contact ───────────────────────────────────────────────── -->
<section id="contact">
<p class="section-label reveal">contact</p>
<div class="contact-inner reveal" style="transition-delay:0.1s">
<div>
<h2>Let's <em>talk</em></h2>
<p>
I am currently employed and open to the right software engineering opportunity, particularly
backend or full-stack roles with teams that value thoughtful delivery and technical quality.
</p>
<p>
For professional enquiries, please connect with me on LinkedIn.
</p>
</div> </div>
<div class="contact-links">
<div class="projects-more-row reveal" style="transition-delay:0.22s"> <a href="https://github.com/jayo60013" class="contact-link" target="_blank" rel="noopener">
<button id="projects-see-more" type="button" class="projects-more-btn" aria-expanded="false">See more</button>
</div>
</section>
<div class="divider"></div>
<!-- ─── Contact ───────────────────────────────────────────────── -->
<section id="contact">
<p class="section-label reveal">contact</p>
<div class="contact-inner reveal" style="transition-delay:0.1s">
<div>
<h2>Let's <em>talk</em></h2>
<p>
I am currently employed and open to the right software engineering opportunity, particularly
backend or full-stack roles with teams that value thoughtful delivery and technical quality.
</p>
<p>
For professional enquiries, please connect with me on LinkedIn.
</p>
</div>
<div class="contact-links">
<a href="https://github.com/jayo60013" class="contact-link" target="_blank" rel="noopener">
<span class="contact-link-icon"> <span class="contact-link-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"> <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
<path <path
d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" /> d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z"/>
</svg> </svg>
</span> </span>
<span class="contact-link-label">GitHub</span> <span class="contact-link-label">GitHub</span>
<span class="contact-link-handle">jayo60013</span> <span class="contact-link-handle">jayo60013</span>
</a> </a>
<a href="https://www.linkedin.com/in/jaygatward" class="contact-link" target="_blank" rel="noopener"> <a href="https://www.linkedin.com/in/jaygatward" class="contact-link" target="_blank" rel="noopener">
<span class="contact-link-icon"> <span class="contact-link-icon">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"> <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
<path <path
d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" /> d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
</svg> </svg>
</span> </span>
<span class="contact-link-label">LinkedIn</span> <span class="contact-link-label">LinkedIn</span>
<span class="contact-link-handle">jaygatward</span> <span class="contact-link-handle">jaygatward</span>
</a> </a>
</div>
</div> </div>
</section> </div>
</section>
<!-- ─── Footer ─────────────────────────────────────────────────── --> <!-- ─── Footer ─────────────────────────────────────────────────── -->
<footer> <footer>
<span>umbra.mom — John Gatward</span> <span>umbra.mom — John Gatward</span>
<span> <span>
Source code repository is also self-hosted: <a href="https://gitea.umbra.mom/jay/havox">repository</a> Source code (selfhosted): <a href="https://gitea.umbra.mom/jay/havox">repository</a>
</span> </span>
</footer> </footer>
<script src="script.js"></script> <script src="script.js"></script>
</body> </body>
</html> </html>

116
script.js
View File

@@ -1,26 +1,26 @@
// ─── Scroll reveal ───────────────────────────────────────── // ─── Scroll reveal ─────────────────────────────────────────
const reveals = document.querySelectorAll('.reveal'); const reveals = document.querySelectorAll('.reveal');
const observer = new IntersectionObserver((entries) => { const observer = new IntersectionObserver((entries) => {
entries.forEach(e => { entries.forEach(e => {
if (e.isIntersecting) { if (e.isIntersecting) {
e.target.classList.add('visible'); e.target.classList.add('visible');
observer.unobserve(e.target); observer.unobserve(e.target);
} }
}); });
}, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' }); }, {threshold: 0.1, rootMargin: '0px 0px -40px 0px'});
reveals.forEach(el => observer.observe(el)); reveals.forEach(el => observer.observe(el));
// ─── Active nav link on scroll ────────────────────────────── // ─── Active nav link on scroll ──────────────────────────────
const sections = document.querySelectorAll('section[id]'); const sections = document.querySelectorAll('section[id]');
const navLinks = document.querySelectorAll('.nav-links a'); const navLinks = document.querySelectorAll('.nav-links a');
window.addEventListener('scroll', () => { window.addEventListener('scroll', () => {
let current = ''; let current = '';
sections.forEach(s => { sections.forEach(s => {
if (window.scrollY >= s.offsetTop - 120) current = s.id; if (window.scrollY >= s.offsetTop - 120) current = s.id;
}); });
navLinks.forEach(a => { navLinks.forEach(a => {
a.style.color = a.getAttribute('href') === `#${current}` ? 'var(--mauve)' : ''; a.style.color = a.getAttribute('href') === `#${current}` ? 'var(--mauve)' : '';
}); });
}); });
// ─── Project filters ────────────────────────────────────────────── // ─── Project filters ──────────────────────────────────────────────
@@ -30,57 +30,57 @@ const seeMoreButton = document.querySelector('#projects-see-more');
const DEFAULT_VISIBLE_PROJECTS = 8; const DEFAULT_VISIBLE_PROJECTS = 8;
if (filterChips.length > 0 && projectCards.length > 0) { if (filterChips.length > 0 && projectCards.length > 0) {
let selectedFilter = 'all'; let selectedFilter = 'all';
let isExpanded = false; let isExpanded = false;
const applyFilter = () => { const applyFilter = () => {
const visibleCards = []; const visibleCards = [];
projectCards.forEach(card => { projectCards.forEach(card => {
const tech = (card.dataset.tech || '').split(/\s+/).filter(Boolean); const tech = (card.dataset.tech || '').split(/\s+/).filter(Boolean);
const shouldShow = selectedFilter === 'all' || tech.includes(selectedFilter); const shouldShow = selectedFilter === 'all' || tech.includes(selectedFilter);
card.classList.toggle('is-hidden', !shouldShow); card.classList.toggle('is-hidden', !shouldShow);
if (shouldShow) { if (shouldShow) {
card.classList.remove('is-collapsed'); card.classList.remove('is-collapsed');
visibleCards.push(card); visibleCards.push(card);
} }
});
if (!isExpanded) {
visibleCards.slice(DEFAULT_VISIBLE_PROJECTS).forEach(card => {
card.classList.add('is-collapsed');
});
}
if (seeMoreButton) {
const canExpand = visibleCards.length > DEFAULT_VISIBLE_PROJECTS;
seeMoreButton.hidden = !canExpand;
seeMoreButton.setAttribute('aria-expanded', canExpand && isExpanded ? 'true' : 'false');
seeMoreButton.textContent = isExpanded ? 'See less' : 'See more';
}
};
filterChips.forEach(chip => {
chip.addEventListener('click', () => {
selectedFilter = chip.dataset.filter || 'all';
isExpanded = false;
filterChips.forEach(other => {
other.classList.toggle('active', other === chip);
});
applyFilter();
});
}); });
if (!isExpanded) {
visibleCards.slice(DEFAULT_VISIBLE_PROJECTS).forEach(card => {
card.classList.add('is-collapsed');
});
}
if (seeMoreButton) { if (seeMoreButton) {
const canExpand = visibleCards.length > DEFAULT_VISIBLE_PROJECTS; seeMoreButton.addEventListener('click', () => {
seeMoreButton.hidden = !canExpand; isExpanded = !isExpanded;
seeMoreButton.setAttribute('aria-expanded', canExpand && isExpanded ? 'true' : 'false'); applyFilter();
seeMoreButton.textContent = isExpanded ? 'See less' : 'See more'; });
} }
};
filterChips.forEach(chip => { applyFilter();
chip.addEventListener('click', () => {
selectedFilter = chip.dataset.filter || 'all';
isExpanded = false;
filterChips.forEach(other => {
other.classList.toggle('active', other === chip);
});
applyFilter();
});
});
if (seeMoreButton) {
seeMoreButton.addEventListener('click', () => {
isExpanded = !isExpanded;
applyFilter();
});
}
applyFilter();
} }

1213
style.css

File diff suppressed because it is too large Load Diff