This commit is contained in:
2026-08-08 15:54:38 +02:00
parent 81f8fab51e
commit ee5729e4b7
3 changed files with 173 additions and 252 deletions
+15 -27
View File
@@ -15,13 +15,10 @@
<meta property="og:image" content="https://www.gade.gg/nikolaj.jpg" />
<meta property="og:image:alt" content="Nikolaj Gade" />
<link rel="icon" type="image/png" href="goat.png" />
<link rel="stylesheet" href="/fonts/fonts.css" />
<link rel="stylesheet" href="/fa/css/all.min.css" />
<link rel="stylesheet" href="style.css" />
<!-- Runs before the body paints, so the pre-reveal styles in style.css apply
from the very first frame instead of flashing. -->
<script>document.documentElement.classList.add('js');</script>
</head>
<body>
<!-- CANVAS BACKGROUND -->
@@ -51,7 +48,7 @@
<!-- HERO -->
<section id="home" class="hero">
<div class="hero-content">
<h1 class="hero-name"><span class="hero-name-static">Nikolaj Gade</span></h1>
<h1 class="hero-name">Nikolaj Gade</h1>
<p class="hero-role">Software Developer</p>
<p class="hero-pronouns">they/them · he/him</p>
@@ -85,18 +82,13 @@
</div>
</div>
<div class="scroll-hint">
<span>scroll</span>
<div class="scroll-line"></div>
</div>
</section>
<!-- ABOUT -->
<section id="about" class="section">
<div class="section-inner">
<div class="section-header">
<span class="section-num">01</span>
<h2 class="section-title" aria-label="About"><span class="bracket">&lt;</span>About<span class="bracket">/&gt;</span></h2>
<h2 class="section-title">About</h2>
<div class="section-rule"></div>
</div>
<div class="about-grid">
@@ -121,8 +113,7 @@
<section id="skills" class="section">
<div class="section-inner">
<div class="section-header">
<span class="section-num">02</span>
<h2 class="section-title" aria-label="Skills"><span class="bracket">&lt;</span>Skills<span class="bracket">/&gt;</span></h2>
<h2 class="section-title">Skills</h2>
<div class="section-rule"></div>
</div>
@@ -131,7 +122,7 @@
<div class="lang-cloud">
<span class="lang-tag lang-primary" data-tip="My main language across hundreds of projects throughout more than a decade.">Python</span>
<span class="lang-tag lang-primary" data-tip="Technically I prefer Fish, but who's counting?">Bash</span>
<span class="lang-tag lang-primary" data-tip="Only academic use so far, but one I genuinely enjoy. Especially when pointers are involved.">C</span>
<span class="lang-tag lang-primary" data-tip="Mostly academic, plus Centvrion's hand-written C runtime. One I genuinely enjoy, especially when pointers are involved.">C</span>
<span class="lang-tag lang-primary" data-tip="A handful of small MonoGame projects, alongside academic work.">C#</span>
<span class="lang-tag lang-primary" data-tip="Used heavily across several of my jobs.">SQL</span>
<span class="lang-tag lang-primary" data-tip="Experience from a (now abandoned) web project.">Go</span>
@@ -158,8 +149,7 @@
<section id="projects" class="section">
<div class="section-inner">
<div class="section-header">
<span class="section-num">03</span>
<h2 class="section-title" aria-label="Projects"><span class="bracket">&lt;</span>Projects<span class="bracket">/&gt;</span></h2>
<h2 class="section-title">Projects</h2>
<div class="section-rule"></div>
</div>
@@ -187,7 +177,7 @@
<p>Both are projects I actively maintain and support, with a small but dedicated community of around 500 players.</p>
</div>
<div class="project-tags">
<span data-tip="The clients and all the randomizer logic are Python.">Python</span><span data-tip="PCSX2 is the PS2 emulator; PINE is the protocol I use to read and write its memory while the game runs.">PCSX2 / PINE</span><span data-tip="A lot of poking at the game's RAM to work out where it keeps everything.">Reverse engineering</span><span data-tip="The multiworld platform both randomizers plug into, so a Sly run can share an item pool with any other supported game.">Archipelago</span><span data-tip="Both randomizers are public on GitHub for anyone to read, fork, or build on.">Open source</span>
<span data-tip="The clients and all the randomizer logic are Python.">Python</span><span data-tip="A fast socket IPC into the emulator. Built on the PINE code from the Ratchet &amp; Clank 2 randomizer, then heavily extended.">PCSX2 / PINE</span><span data-tip="Hundreds of hand-mapped memory addresses per game, found by diffing emulator memory.">Reverse engineering</span><span data-tip="Sly isn't in Archipelago core, so each randomizer ships as an apworld package that players drop into their installs.">Archipelago</span><span data-tip="The client is an asyncio app juggling the Archipelago server connection and emulator polling at the same time.">asyncio</span>
</div>
</div>
@@ -209,7 +199,7 @@
<p>The language includes a tree-walking interpreter and a compiler that targets C. Optional modules extend the standard library with <code>FORS</code> (random numbers), <code>FRACTIO</code> (base-12 fractions for floats), <code>MAGNVM</code> (higher numbers than standard roman numerals), and <code>SVBNVLLA</code> (negative numbers).</p>
</div>
<div class="project-tags">
<span data-tip="Both the interpreter and the compiler are written in Python.">Python</span><span data-tip="Designed deliberately: grammar, keywords, and semantics planned out with the rigor of my programming-language coursework.">Language design</span><span data-tip="Targets C, which then compiles down to a native binary.">Compiler</span><span data-tip="A tree-walking interpreter for running code directly.">Interpreter</span>
<span data-tip="Both the interpreter and the compiler are written in Python.">Python</span><span data-tip="Planned like my programming-language coursework: keywords, semantics, and a formal grammar written up in LaTeX.">Language design</span><span data-tip="Emits C against a small hand-written runtime (Roman-numeral formatting included), then hands off to the system compiler.">Compiler</span><span data-tip="A pygls language server with live diagnostics and hover docs, so your editor can correct your Latin.">LSP</span>
</div>
</div>
@@ -235,11 +225,11 @@
</div>
</div>
<div class="project-body">
<p>A trading card game where every card is generated from a Wikipedia article. Built for friends, it features booster pack opening, a fully implemented card game, and trading between players. It also, naturally, includes predatory microtransactions.</p>
<p>A trading card game where every card is generated from a Wikipedia article. Built for friends, it features booster pack opening, a fully implemented card game, and trading between players. Matches run in real time against friends or AI opponents, one of which is a neural network trained through self-play. It also, naturally, includes predatory microtransactions.</p>
<p>The frontend is built in Svelte and the backend in Python, deployed with Docker Compose.</p>
</div>
<div class="project-tags">
<span data-tip="The whole frontend: pack opening, trading, and the card game itself.">Svelte</span><span data-tip="Backend, card generation, and game logic.">Python</span><span data-tip="I hardly know 'er!">Docker</span><span data-tip="Every card is generated from a real Wikipedia article, and the data is gathered from calls to the Wikipedia, Wikimedia, and WikiRank APIs.">APIs</span><span data-tip="Frontend, backend, and everything between.">Full-stack</span>
<span data-tip="SvelteKit with the static adapter, so the whole frontend is static files talking to the API.">Svelte</span><span data-tip="A FastAPI app: REST for the site, WebSockets for live games and trades.">Python</span><span data-tip="I hardly know 'er!">Docker</span><span data-tip="Wikipedia, Wikimedia, and WikiRank for card generation; Stripe and Resend for payments and email.">APIs</span><span data-tip="Eight AI personalities to play against, including one driven by a neural network written from scratch in numpy and trained by self-play.">Game AI</span><span data-tip="SQLAlchemy with Alembic migrations. The app role can't touch the schema; only the migration role can.">PostgreSQL</span>
</div>
</div>
@@ -254,12 +244,12 @@
</div>
<div class="project-body">
<p>Born out of a deep distrust of Microsoft and Google, this project is my ongoing effort to self-host as much of my digital life as possible. Every device on my network is named after a Pokémon and assigned a local IP of <code>10.0.0.x</code>, where <code>x</code> is its Pokédex number.</p>
<p>The primary server, <strong>Charizard</strong>, runs Unraid OS and manages a disk array totalling 44 TB. It hosts a Gitea instance for personal projects, a file server, and a media server, all running in Docker containers and exposed to the internet through <strong>Nginx Proxy Manager</strong> with SSL certificates from Let's Encrypt.</p>
<p>The primary server, <strong>Charizard</strong>, runs Unraid OS and manages a disk array totalling 44 TB. It hosts a Gitea instance for personal projects, a file server, and a media server, exposed to the internet through <strong>Nginx Proxy Manager</strong> with SSL certificates from Let's Encrypt.</p>
<p>An extension of the setup lives on <strong>Bulbasaur</strong>, a Raspberry Pi running Pi-hole for network-wide ad blocking and a WireGuard VPN server for secure remote access.</p>
<p>Charizard is turning five this year. In that time I've learned an enormous amount about networking, Linux administration, and the particular satisfaction of fixing something broken at 2 in the morning that nobody asked you to build in the first place.</p>
</div>
<div class="project-tags">
<span data-tip="The OS on Charizard, managing the 44 TB disk array.">Unraid</span><span data-tip="Every service runs in its own container.">Docker</span><span data-tip="Nginx Proxy Manager routes traffic to each service, with Let's Encrypt SSL.">Reverse Proxy</span><span data-tip="Subnetting, DNS, and a VPN.">Networking</span><span data-tip="The thing that it is.">Self-hosting</span>
<span data-tip="The OS on Charizard, chosen mainly because it supports mixed-size drives. Currently it sports 3 different sizes of data disks (4x6TB + 12TB + 8TB).">Unraid</span><span data-tip="Every service runs in its own container.">Docker</span><span data-tip="Each service gets its own subdomain; no container publishes a port directly.">Reverse Proxy</span><span data-tip="Subnetting, DNS, and a VPN.">Networking</span><span data-tip="The thing that it is.">Self-hosting</span>
</div>
</div>
@@ -271,8 +261,7 @@
<section id="experience" class="section">
<div class="section-inner">
<div class="section-header">
<span class="section-num">04</span>
<h2 class="section-title" aria-label="Experience"><span class="bracket">&lt;</span>Experience<span class="bracket">/&gt;</span></h2>
<h2 class="section-title">Experience</h2>
<div class="section-rule"></div>
</div>
<div class="timeline">
@@ -280,7 +269,7 @@
<div class="timeline-marker"></div>
<div class="timeline-card">
<div class="timeline-meta">
<span class="timeline-date">Sep 2024 — Present</span>
<span class="timeline-date">Sep 2024 — Jul 2026</span>
<span class="timeline-tag">Part-time</span>
</div>
<h3 class="timeline-role">Junior Developer</h3>
@@ -331,8 +320,7 @@
<section id="education" class="section">
<div class="section-inner">
<div class="section-header">
<span class="section-num">05</span>
<h2 class="section-title" aria-label="Education"><span class="bracket">&lt;</span>Education<span class="bracket">/&gt;</span></h2>
<h2 class="section-title">Education</h2>
<div class="section-rule"></div>
</div>
<div class="education-grid">