Added notes to V1

This commit is contained in:
John Gatward
2026-03-21 00:32:03 +00:00
parent d4ca596cdd
commit 6f313c8d49
8 changed files with 519 additions and 381 deletions

View File

@@ -62,8 +62,7 @@
</div> </div>
<div class="nf-actions"> <div class="nf-actions">
<a href="index.html" class="btn btn-primary">← Back home</a> <a href="/" class="btn btn-primary">← Back home</a>
<a href="index.html#projects" class="btn btn-ghost">View projects</a>
</div> </div>
</main> </main>

View File

@@ -10,12 +10,12 @@
<script src="/frameworks/jquery-3.3.1.min.js"></script> <script src="/frameworks/jquery-3.3.1.min.js"></script>
<script src="/frameworks/bootstrap.min.js"></script> <script src="/frameworks/bootstrap.min.js"></script>
<link rel='stylesheet prefetch' href='https://netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.css'> <link rel='stylesheet prefetch' href='https://netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.css'>
<link rel="stylesheet" href="style.css" /> <link rel="stylesheet" href="style.css"/>
</head> </head>
<body> <body>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation"> <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container"> <div class="container">
<div class="navbar-header"> <div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
@@ -39,9 +39,9 @@
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
<div class="container-fluid big-logo-row"> <div class="container-fluid big-logo-row">
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-xs-12 big-logo-container"> <div class="col-xs-12 big-logo-container">
@@ -49,15 +49,17 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-lg-9 col-md-8 col-sm-12"> <div class="col-lg-9 col-md-8 col-sm-12">
<h2>Welcome to my website</h2> <h2>Welcome to my website</h2>
<div class="contents"> <div class="contents">
<div id="quoteJump" class="quoteDiv"> <div id="quoteJump" class="quoteDiv">
<h3>Quote of the day</h3> <h3>Quote of the day</h3>
<p class="v4-margin-note">The original
python webscraper script no longer works, the below quote is just a placeholder.</p>
<p><b>Quote: </b> <p><b>Quote: </b>
Try to keep your soul young and quivering right up to old age. Try to keep your soul young and quivering right up to old age.
</p> </p>
@@ -67,36 +69,9 @@
</div> </div>
<div class="intro"> <div class="intro">
<h3 id="introjump">About me</h3> <h3 id="introjump">About me</h3>
<p class="v4-margin-note">The original
<p>The Union of the indestructible republics of the free ones about me section was full of nonsense memes and has been removed.</p>
The Great Russia has forever consolidated itself. <p>A cool website to show my projects</p>
Long live the people created by the will of the people
A single, mighty Soviet Union!</p>
<p>Be glorious, our free Fatherland,
Friendship, peoples a reliable stronghold!
The Soviet banner, the banner of the people
Let it lead from victory to victory!</p>
<p>Through the thunderstorms the sun of freedom shone,
And Lenin, the great one, illumined our way.
We were brought up by Stalin - to be faithful to the people.
We were inspired by work and deeds.</p>
<p>Be glorious, Fatherland freer,
Happiness of peoples reliable stronghold!
The Soviet banner, the banner of the people
Let it lead from victory to victory!</p>
<p>We raised our army in the battles,
The invaders of the vile from the road are estimated!
We are in the battles to decide the fate of generations,
We will lead our glory to our Fatherland!</p>
<p>Be glorious, our free Fatherland,
the glory of peoples is a reliable stronghold!
The Soviet banner, the banner of the people
Let it lead from victory to victory!</p>
</div> </div>
<div class="projects"> <div class="projects">
@@ -192,10 +167,10 @@
</div> </div>
</div><!--/.col-xs-12 --> </div><!--/.col-xs-12 -->
</div><!--/.row --> </div><!--/.row -->
</div><!--/.container --> </div><!--/.container -->
<script src="script.js"> <script src="script.js">
</script> </script>
</body> </body>
<footer> <footer>

View File

@@ -1,4 +1,4 @@
body{ body {
overflow-x: hidden; overflow-x: hidden;
} }
@@ -8,7 +8,10 @@ body{
border-bottom: none; border-bottom: none;
} }
a{font-family: 'Roboto Condensed', sans-serif;} a {
font-family: 'Roboto Condensed', sans-serif;
}
.navbar-inverse .navbar-toggle { .navbar-inverse .navbar-toggle {
border: 1px solid #333; border: 1px solid #333;
border-color: rgba(0, 0, 0, 0.7); border-color: rgba(0, 0, 0, 0.7);
@@ -61,35 +64,42 @@ a{font-family: 'Roboto Condensed', sans-serif;}
background: white; background: white;
color: black; color: black;
} }
.big-logo-row .big-logo-container { .big-logo-row .big-logo-container {
padding-top: 50px; padding-top: 50px;
} }
.big-logo-row h1 { .big-logo-row h1 {
font-size: 4em; font-size: 4em;
margin: 0; margin: 0;
padding: 0 0 15px 0; padding: 0 0 15px 0;
} }
@media (min-width: 400px) { @media (min-width: 400px) {
.big-logo-row h1 { .big-logo-row h1 {
font-size: 4.5em; font-size: 4.5em;
} }
} }
@media (min-width: 440px) { @media (min-width: 440px) {
.big-logo-row h1 { .big-logo-row h1 {
font-size: 5.5em; font-size: 5.5em;
} }
} }
@media (min-width: 500px) { @media (min-width: 500px) {
.big-logo-row h1 { .big-logo-row h1 {
font-size: 6.5em; font-size: 6.5em;
} }
} }
@media (min-width: 630px) { @media (min-width: 630px) {
.big-logo-row h1 { .big-logo-row h1 {
font-size: 7.5em; font-size: 7.5em;
overflow-x: hidden; overflow-x: hidden;
} }
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.big-logo-row h1 { .big-logo-row h1 {
font-size: 9em; font-size: 9em;
@@ -97,6 +107,7 @@ a{font-family: 'Roboto Condensed', sans-serif;}
overflow-x: hidden; overflow-x: hidden;
} }
} }
@media (min-width: 1200px) { @media (min-width: 1200px) {
.big-logo-row h1 { .big-logo-row h1 {
font-size: 12em; font-size: 12em;
@@ -104,38 +115,38 @@ a{font-family: 'Roboto Condensed', sans-serif;}
} }
} }
h2{ h2 {
font-size: 41px; font-size: 41px;
font-weight: bold; font-weight: bold;
font-family: 'Roboto Condensed', sans-serif; font-family: 'Roboto Condensed', sans-serif;
color: black; color: black;
} }
p{ p {
font-size: 20px; font-size: 20px;
font-family: 'Roboto Condensed', sans-serif; font-family: 'Roboto Condensed', sans-serif;
color: #333; color: #333;
text-decoration: none; text-decoration: none;
} }
h3{ h3 {
text-align: center; text-align: center;
font-size: 30px; font-size: 30px;
font-family: 'Roboto Condensed', sans-serif; font-family: 'Roboto Condensed', sans-serif;
color: black; color: black;
} }
.projects, .intro{ .projects, .intro {
border-bottom: thin solid #333; border-bottom: thin solid #333;
} }
.picturebox{ .picturebox {
list-style-type: none; list-style-type: none;
float: left; float: left;
} }
footer{ footer {
padding: 20px; padding: 20px;
background-color: #e0e0e0; background-color: #e0e0e0;
font-family: 'Roboto Condensed', sans-serif; font-family: 'Roboto Condensed', sans-serif;
@@ -167,7 +178,7 @@ ul {
} }
#overlay { #overlay {
background: rgba(0,0,0, .8); background: rgba(0, 0, 0, .8);
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute; position: absolute;
@@ -191,3 +202,43 @@ ul {
width: 100%; width: 100%;
} }
.v4-margin-note {
position: relative;
margin: 4px 0 20px 0;
padding: 30px 16px 12px 16px;
border-left: 2px solid rgba(243, 139, 168, 0.6);
background: linear-gradient(135deg, rgba(243, 139, 168, 0.07) 0%, rgba(243, 139, 168, 0.02) 60%, transparent 100%);
color: #3d3f53;
font-size: 13px;
line-height: 1.65;
font-family: 'JetBrains Mono', 'Courier New', monospace;
font-style: italic;
max-width: 680px;
border-radius: 0 6px 6px 0;
box-shadow: inset 0 0 0 1px rgba(243, 139, 168, 0.07), 2px 2px 8px rgba(0, 0, 0, 0.04);
}
.v4-margin-note::before {
content: '✎ archived note';
position: absolute;
top: 9px;
left: 16px;
color: rgba(243, 139, 168, 0.85);
font-size: 10px;
font-style: normal;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.12em;
font-family: 'JetBrains Mono', 'Courier New', monospace;
}
.v4-margin-note::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, rgba(243, 139, 168, 0.4), transparent);
border-radius: 0 6px 0 0;
}

4
icons/github.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
<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" />
</svg>

After

Width:  |  Height:  |  Size: 769 B

4
icons/linkedin.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
<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" />
</svg>

After

Width:  |  Height:  |  Size: 541 B

View File

@@ -4,9 +4,9 @@
<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</title>
<meta name="description" <meta name="description"
content="John Gatward's portfolio: software engineering projects spanning backend systems, infrastructure, and creative developer experiments."/> content="John Gatward's portfolio"/>
<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"
@@ -29,7 +29,7 @@
<!-- ─── 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">
@@ -39,7 +39,6 @@
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>
</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>
@@ -61,28 +60,26 @@
<!-- 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">
<p>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.</p>
</div>
<div class="about-block"> <div class="about-block">
<span class="about-block-tag tag tag-blue">day job</span> <span class="about-block-tag tag tag-blue">day job</span>
<p>Backend engineer at <strong>Sainsbury's</strong> Supply Chain &amp; Logistics. Microservices, <p>Backend engineer at <strong>Sainsbury's</strong> Supply Chain &amp; Logistics. It's good fun.</p>
Spring Boot, Kafka, MongoDB, AWS. It's good fun.</p>
</div> </div>
<div class="about-block"> <div class="about-block">
<span class="about-block-tag tag tag-teal">dev</span> <span class="about-block-tag tag tag-teal">dev</span>
<p>Fascinated with new languages, frameworks, and shiny tech I probably dont need. Constantly <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> learning just enough to build something slightly cooler next time.</p>
</div> </div>
<div class="about-block"> <div class="about-block">
<span class="about-block-tag tag tag-yellow">linux</span> <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 <p>Long-time Linux user and distro-hopper. Self-hosted server running 24/7 for friends and family who
running 24/7 for friends and family who didn't ask for it but appreciate it.</p> didn't ask for it but <s>probably</s> definitely 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>
</div> </div>
@@ -97,7 +94,7 @@
<div class="v-content"> <div class="v-content">
<div class="v-title">Havox V4 <span class="v-current-badge">current</span></div> <div class="v-title">Havox V4 <span class="v-current-badge">current</span></div>
<div class="v-year">2026 → present</div> <div class="v-year">2026 → present</div>
<div class="v-desc">Catppuccin Mocha. Single page. Built to highlight projects and craft.</div> <div class="v-desc">Catppuccin Mocha. Single page. Professional.</div>
</div> </div>
</div> </div>
@@ -106,7 +103,9 @@
<div class="v-content"> <div class="v-content">
<div class="v-title">Havox V3 <span class="v-link-arrow"></span></div> <div class="v-title">Havox V3 <span class="v-link-arrow"></span></div>
<div class="v-year">2022 → 2025</div> <div class="v-year">2022 → 2025</div>
<div class="v-desc">Borrowed a professional looking template. Wasn't very 'me'.</div> <div class="v-desc">Borrowed a professional template and tried to make it suit my needs. Wasn't
very 'me'.
</div>
</div> </div>
</a> </a>
@@ -115,7 +114,9 @@
<div class="v-content"> <div class="v-content">
<div class="v-title">Umbra.cyou <span class="v-link-arrow"></span></div> <div class="v-title">Umbra.cyou <span class="v-link-arrow"></span></div>
<div class="v-year">2019 → 2022</div> <div class="v-year">2019 → 2022</div>
<div class="v-desc">Complete redesign using SCSS & Nord theme.</div> <div class="v-desc">Built from the ground up focusing on a minimal clean design. Stole my code
VS Code theme for a colour palette.
</div>
</div> </div>
</a> </a>
@@ -124,8 +125,7 @@
<div class="v-content"> <div class="v-content">
<div class="v-title">Havox.org <span class="v-link-arrow"></span></div> <div class="v-title">Havox.org <span class="v-link-arrow"></span></div>
<div class="v-year">2016 → 2019</div> <div class="v-year">2016 → 2019</div>
<div class="v-desc">Entire site in one PHP file 🤣. Had a daily <s>trump</s> <div class="v-desc">Wrote the entire site in one php file. Hosted on a £1/year VPS.
quote-of-the-day achieved via webscraping a site daily.
</div> </div>
</div> </div>
</a> </a>
@@ -147,8 +147,8 @@
<div class="skill-card reveal"> <div class="skill-card reveal">
<span class="skill-card-icon"></span> <span class="skill-card-icon"></span>
<h3>Backend</h3> <h3>Backend</h3>
<p>Professional Java experience building microservices &amp; RESTful APIs with Spring Boot. TDD with <p>Professional experience designing, building and deploying services. Using a modern tech stack in the
JUnit & Mockito.</p> Supply Chain & Logistics industry.</p>
<div class="tag-row"> <div class="tag-row">
<span class="tag tag-blue">Java</span> <span class="tag tag-blue">Java</span>
<span class="tag tag-green">Spring Boot</span> <span class="tag tag-green">Spring Boot</span>
@@ -160,8 +160,8 @@
<div class="skill-card reveal" style="transition-delay:0.08s"> <div class="skill-card reveal" style="transition-delay:0.08s">
<span class="skill-card-icon">🎨</span> <span class="skill-card-icon">🎨</span>
<h3>Frontend & Creative</h3> <h3>Frontend & Creative</h3>
<p>Comfortable with react and CSS. I enjoy visualising algorithms interactively it's more fun than <p>Comfortable with React and CSS. I've always enjoyed visualising algorithms interactively - it's way more
a console output.</p> fun than a console output.</p>
<div class="tag-row"> <div class="tag-row">
<span class="tag tag-teal">React</span> <span class="tag tag-teal">React</span>
<span class="tag tag-green">TypeScript</span> <span class="tag tag-green">TypeScript</span>
@@ -171,8 +171,8 @@
<div class="skill-card reveal" style="transition-delay:0.16s"> <div class="skill-card reveal" style="transition-delay:0.16s">
<span class="skill-card-icon">🖥</span> <span class="skill-card-icon">🖥</span>
<h3>Systems & Infra</h3> <h3>Systems & Infra</h3>
<p>Long-term Linux user. Self-hosted web & media servers. Comfortable with networking, security <p>Long-term Linux & Vim user. Self-hosted web & media servers. Using industry practices when it comes to
practices, and the command line.</p> networks & security.</p>
<div class="tag-row"> <div class="tag-row">
<span class="tag tag-green">Linux</span> <span class="tag tag-green">Linux</span>
<span class="tag tag-teal">Docker</span> <span class="tag tag-teal">Docker</span>
@@ -204,7 +204,8 @@
<p class="section-label reveal">projects</p> <p class="section-label reveal">projects</p>
<h2 class="section-heading reveal" style="transition-delay:0.05s">Things I <em>built</em></h2> <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"> <p class="section-intro reveal" style="transition-delay:0.1s">
A timeline of fun projects used as an excuse to learn something new. 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.
</p> </p>
<div class="projects-subheading reveal" style="transition-delay:0.12s"> <div class="projects-subheading reveal" style="transition-delay:0.12s">
@@ -215,8 +216,7 @@
<a class="card" href="https://wordlesolver.umbra.mom"> <a class="card" href="https://wordlesolver.umbra.mom">
<span class="card-date">9 Feb 2025</span> <span class="card-date">9 Feb 2025</span>
<span class="card-title">Wordle Solver</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 <span class="card-desc">Built 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>
@@ -227,7 +227,7 @@
<a class="card" href="https://crackthequote.umbra.mom"> <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. Built for me and my family to play after getting bored with NYT games.</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>
@@ -254,16 +254,17 @@
</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"> <article class="card project-card card-link" data-tech="python" data-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 our local pub quiz performances.</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> </article>
<a class="card project-card" data-tech="cpp webassembly" href="projects/thin_ice/thin_ice.html"> <article class="card project-card card-link" data-tech="cpp webassembly"
data-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>
@@ -273,90 +274,96 @@
<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> </article>
<a class="card project-card" data-tech="zig webassembly" href="projects/tsp/index.html"> <article class="card project-card card-link" data-tech="zig webassembly" data-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. Wanted to revisit one of my first projects but with a super optimised tech-stack & algorithm.</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> </article>
<a class="card project-card" data-tech="rust" href="projects/flocking/index.html"> <article class="card project-card card-link" data-tech="rust" data-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">Rewrote the entire project in Rust from GoLang to compile to wasm. Was fun being able to use DOM controls to affect the simulation.</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> </article>
<a class="card project-card" data-tech="javascript" href="https://samstoreymusic.com"> <article class="card project-card card-link" data-tech="javascript" data-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. Saving him the hosting fees :)</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> </article>
<a class="card project-card" data-tech="javascript react" href="projects/cellular_automata/index.html"> <article class="card project-card card-link" data-tech="javascript react"
data-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 as one of my first projects, 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> </article>
<a class="card project-card" data-tech="cpp webassembly" href="projects/percolation/index.html"> <article class="card project-card card-link" data-tech="cpp webassembly"
data-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">Watched a brilliant video by <a target="_blank"
href="https://youtu.be/a-767WnbaCQ?si=f3NM95INeoZqzIi8">Spectral Collective</a> and just had to recreate it.</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> </article>
<a class="card project-card" data-tech="javascript p5" href="projects/cubic_bezier_curve/index.html"> <article class="card project-card card-link" data-tech="javascript p5"
data-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 animation for how cubic Bézier curves are constructed. Inspirated by this beautiful video by <a
target="_blank" href="https://youtu.be/aVwxzDHniEw?si=mCylw_p-fMSdhyvN">Fraya Holmér</a></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> </article>
<a class="card project-card" data-tech="javascript p5" href="projects/marching_squares.html"> <article class="card project-card card-link" data-tech="javascript p5"
data-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">I saw the 3D version of this algorithm in a game dev log and was inspired to create this 2d land/sea map generator thing.</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> </article>
<a class="card project-card" data-tech="javascript p5" href="projects/warping_lines.html"> <article class="card project-card card-link" data-tech="javascript p5" data-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">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> </article>
<a class="card project-card" data-tech="javascript p5" href="projects/fourier_series.html"> <article class="card project-card card-link" data-tech="javascript p5" data-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>
@@ -365,18 +372,21 @@
<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> </article>
<a class="card project-card" data-tech="javascript p5" href="projects/ellipse_construction.html"> <article class="card project-card card-link" data-tech="javascript p5"
data-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 <a target="_blank"
href="https://youtu.be/xdIjYBtnvZU?si=uI66LS_O_eAWqG4e">3Blue1Brown's video</a> on Feynman's lost lecture.</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> </article>
<a class="card project-card" data-tech="javascript p5" href="projects/pi_approximation.html"> <article class="card project-card card-link" data-tech="javascript p5"
data-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>
@@ -385,8 +395,9 @@
<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> </article>
<a class="card project-card" data-tech="javascript p5" href="projects/oscillations_in_3d.html"> <article class="card project-card card-link" data-tech="javascript p5"
data-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>
@@ -395,17 +406,19 @@
<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> </article>
<a class="card project-card" data-tech="javascript p5" href="projects/maze_generation/index.html"> <article class="card project-card card-link" data-tech="javascript p5"
data-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">Discovered the <a target="_blank"
href="https://youtu.be/HyK_Q5rrcr4?si=G6g8xDHK0cc_MwhG">Coding Train's channel</a> and learnt coding through following along.</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> </article>
</div> </div>
<div class="projects-more-row reveal" style="transition-delay:0.22s"> <div class="projects-more-row reveal" style="transition-delay:0.22s">
@@ -423,30 +436,20 @@
<h2>Let's <em>talk</em></h2> <h2>Let's <em>talk</em></h2>
<p> <p>
I am currently employed and open to the right software engineering opportunity, particularly 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. backend or full-stack roles with friendly, close-knit teams.
</p> </p>
<p> <p>
For professional enquiries, please connect with me on LinkedIn. For professional enquiries, please contact me on LinkedIn.
</p> </p>
</div> </div>
<div class="contact-links"> <div class="contact-links">
<a href="https://github.com/jayo60013" class="contact-link" target="_blank" rel="noopener"> <a href="https://github.com/jayo60013" class="contact-link" target="_blank" rel="noopener">
<span class="contact-link-icon"> <span class="contact-link-icon contact-link-icon--github" aria-hidden="true"></span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
<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"/>
</svg>
</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 contact-link-icon--linkedin" aria-hidden="true"></span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
<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"/>
</svg>
</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>
@@ -456,7 +459,7 @@
<!-- ─── Footer ─────────────────────────────────────────────────── --> <!-- ─── Footer ─────────────────────────────────────────────────── -->
<footer> <footer>
<span>umbra.mom John Gatward</span> <span>umbra.mom - John Gatward</span>
<span> <span>
Source code (selfhosted): <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>

View File

@@ -32,6 +32,22 @@ const DEFAULT_VISIBLE_PROJECTS = 9;
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 interactiveSelector = 'a, button, input, textarea, select, summary, [role="button"]';
const goToCardHref = (card, event) => {
const href = card.dataset.href;
if (!href) {
return;
}
const openInNewTab = event.metaKey || event.ctrlKey || event.button === 1;
if (openInNewTab) {
window.open(href, '_blank', 'noopener');
return;
}
globalThis.location.href = href;
};
const applyFilter = () => { const applyFilter = () => {
const visibleCards = []; const visibleCards = [];
@@ -81,6 +97,47 @@ if (filterChips.length > 0 && projectCards.length > 0) {
}); });
} }
projectCards.forEach(card => {
if (!card.dataset.href) {
return;
}
card.setAttribute('role', 'link');
card.setAttribute('tabindex', '0');
card.addEventListener('click', event => {
const target = event.target;
if (!(target instanceof Element)) {
return;
}
// Let inline links and other controls inside the card handle their own clicks.
if (target.closest(interactiveSelector) && target.closest(interactiveSelector) !== card) {
return;
}
goToCardHref(card, event);
});
card.addEventListener('keydown', event => {
if (event.key !== 'Enter' && event.key !== ' ') {
return;
}
const target = event.target;
if (!(target instanceof Element)) {
return;
}
if (target.closest(interactiveSelector) && target.closest(interactiveSelector) !== card) {
return;
}
event.preventDefault();
goToCardHref(card, event);
});
});
applyFilter(); applyFilter();
} }

View File

@@ -39,7 +39,13 @@ html {
} }
body { body {
background: var(--base); 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%),
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); color: var(--text);
font-family: 'JetBrains Mono', 'Apple Color Emoji', monospace; font-family: 'JetBrains Mono', 'Apple Color Emoji', monospace;
font-size: 15px; font-size: 15px;
@@ -52,25 +58,27 @@ body::before,
body::after { body::after {
content: ''; content: '';
position: fixed; position: fixed;
width: 36rem; width: 52rem;
height: 36rem; height: 42rem;
border-radius: 50%; border-radius: 58% 42% 55% 45% / 46% 54% 48% 52%;
pointer-events: none; pointer-events: none;
z-index: -1; z-index: -1;
filter: blur(70px); filter: blur(90px);
opacity: 0.12; opacity: 0.16;
} }
body::before { body::before {
top: -10rem; top: -18rem;
right: -10rem; right: -16rem;
background: radial-gradient(circle, var(--mauve), transparent 65%); transform: rotate(14deg);
background: radial-gradient(closest-side at 38% 42%, rgba(203, 166, 247, 0.42), transparent 72%);
} }
body::after { body::after {
bottom: -14rem; bottom: -20rem;
left: -12rem; left: -18rem;
background: radial-gradient(circle, var(--blue), transparent 65%); transform: rotate(-12deg);
background: radial-gradient(closest-side at 60% 58%, rgba(137, 180, 250, 0.36), transparent 72%);
} }
::selection { ::selection {
@@ -269,11 +277,6 @@ section.full-width {
opacity: 0.8; opacity: 0.8;
} }
.hero-by-role::before {
content: '— ';
opacity: 0.4;
}
.hero-by-footer { .hero-by-footer {
display: block; display: block;
margin-top: 1rem; margin-top: 1rem;
@@ -373,6 +376,12 @@ section.full-width {
gap: 1.25rem; 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);
}
.about-block:last-child { .about-block:last-child {
border-bottom: none; border-bottom: none;
} }
@@ -771,6 +780,15 @@ section.full-width {
overflow: hidden; overflow: hidden;
} }
.card-link {
cursor: pointer;
}
.card-link:focus-visible {
outline: 1px solid var(--mauve);
outline-offset: -1px;
}
.card::before { .card::before {
content: ''; content: '';
position: absolute; position: absolute;
@@ -817,6 +835,16 @@ section.full-width {
flex: 1; flex: 1;
} }
.card-desc a {
color: var(--sky);
text-decoration: underline;
text-underline-offset: 2px;
}
.card-desc a:hover {
color: var(--mauve);
}
.card-arrow { .card-arrow {
font-size: 0.8rem; font-size: 0.8rem;
color: var(--overlay0); color: var(--overlay0);
@@ -894,9 +922,26 @@ section.full-width {
} }
.contact-link-icon { .contact-link-icon {
font-size: 1.1rem; width: 1.125rem;
width: 1.5rem; height: 1.125rem;
text-align: center; 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');
}
.contact-link-icon--linkedin {
-webkit-mask-image: url('icons/linkedin.svg');
mask-image: url('icons/linkedin.svg');
} }
.contact-link-label { .contact-link-label {