Remove extra tags
This commit is contained in:
parent
11796a8869
commit
82c723c192
18 changed files with 4 additions and 93 deletions
|
|
@ -13,16 +13,11 @@ links:
|
||||||
url: https://github.com/schmelczer/backup-container/pkgs/container/backup-container
|
url: https://github.com/schmelczer/backup-container/pkgs/container/backup-container
|
||||||
article:
|
article:
|
||||||
tags: ['systems', 'tools']
|
tags: ['systems', 'tools']
|
||||||
role: Container and script author
|
|
||||||
stack: ['Bash', 'BorgBackup', 'BTRFS', 'Alpine', 'Docker', 'SSH', 'zstd']
|
stack: ['Bash', 'BorgBackup', 'BTRFS', 'Alpine', 'Docker', 'SSH', 'zstd']
|
||||||
scale: One container, multiple targets per host, two years of restored incidents
|
scale: One container, multiple targets per host, two years of restored incidents
|
||||||
outcome: A self-hosted backup that has survived every actual incident I've thrown at it
|
outcome: A self-hosted backup that has survived every actual incident I've thrown at it
|
||||||
audience: technical
|
|
||||||
project:
|
project:
|
||||||
title: Backup Container
|
title: Backup Container
|
||||||
description: A Bash container around BorgBackup. BTRFS snapshot for atomic consistency, numeric env vars for multi-target 3-2-1, sleep-loop instead of cron.
|
|
||||||
thumbnail:
|
|
||||||
alt: Placeholder thumbnail for the backup container project.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Once you self-host a few services with live databases, the backup question stops being theoretical: everything on the box is mid-write at every moment of the day. This container is my answer, two years and several real restores in (including the photo library behind the [e-ink frame](/articles/frame-eink-photo-display/)). One Alpine container and four short shell scripts (the longest is 84 lines) push a BTRFS snapshot to one or more [Borg](https://borgbackup.readthedocs.io/) repositories on a fixed interval. Multi-target is numeric env vars (`BORG_REPO_0`, `BORG_REPO_1`, ...); there's no config format and no DSL, because the env file is the configuration. The design has exactly one clever moment, the snapshot, and I've worked to keep everything else too simple to break.
|
Once you self-host a few services with live databases, the backup question stops being theoretical: everything on the box is mid-write at every moment of the day. This container is my answer, two years and several real restores in (including the photo library behind the [e-ink frame](/articles/frame-eink-photo-display/)). One Alpine container and four short shell scripts (the longest is 84 lines) push a BTRFS snapshot to one or more [Borg](https://borgbackup.readthedocs.io/) repositories on a fixed interval. Multi-target is numeric env vars (`BORG_REPO_0`, `BORG_REPO_1`, ...); there's no config format and no DSL, because the env file is the configuration. The design has exactly one clever moment, the snapshot, and I've worked to keep everything else too simple to break.
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ thumbnail:
|
||||||
alt: Screenshot of a Unity traffic simulation.
|
alt: Screenshot of a Unity traffic simulation.
|
||||||
article:
|
article:
|
||||||
tags: ['simulation', 'systems']
|
tags: ['simulation', 'systems']
|
||||||
role: Simulation author
|
|
||||||
stack: ['Unity', 'C#', 'REST API', 'Blender']
|
stack: ['Unity', 'C#', 'REST API', 'Blender']
|
||||||
outcome: Visible consequences for an otherwise abstract PLC challenge
|
outcome: Visible consequences for an otherwise abstract PLC challenge
|
||||||
audience: technical
|
|
||||||
project:
|
project:
|
||||||
title: City Simulation
|
title: City Simulation
|
||||||
description: A Unity city where REST-controlled traffic lights made bad PLC code visible as car crashes.
|
|
||||||
thumbnail:
|
|
||||||
alt: Screenshot of a Unity city traffic simulation.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Most security challenges punish a wrong answer with a red "incorrect". This one punished it with car wrecks. For a PLC cybersecurity event in the summer of 2018, I built a small Unity city where the traffic lights were driven over a REST API by whatever control logic the contestants wrote. Good logic produced boring, flowing traffic. Bad logic produced intersections that people gathered around to watch.
|
Most security challenges punish a wrong answer with a red "incorrect". This one punished it with car wrecks. For a PLC cybersecurity event in the summer of 2018, I built a small Unity city where the traffic lights were driven over a REST API by whatever control logic the contestants wrote. Good logic produced boring, flowing traffic. Bad logic produced intersections that people gathered around to watch.
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,9 @@ links:
|
||||||
download: true
|
download: true
|
||||||
article:
|
article:
|
||||||
tags: ['games', 'web', 'systems']
|
tags: ['games', 'web', 'systems']
|
||||||
role: Game and backend systems author
|
|
||||||
stack: ['TypeScript', 'Node.js', 'WebSockets', 'WebGL', 'SDF-2D']
|
stack: ['TypeScript', 'Node.js', 'WebSockets', 'WebGL', 'SDF-2D']
|
||||||
scale: Game servers ticking at 200 Hz, each serving 16–32 clients at 25 updates a second, browser and mobile
|
scale: Game servers ticking at 200 Hz, each serving 16–32 clients at 25 updates a second, browser and mobile
|
||||||
outcome: A multiplayer browser game that proved SDF-2D survived a real game loop
|
outcome: A multiplayer browser game that proved SDF-2D survived a real game loop
|
||||||
audience: technical
|
|
||||||
media:
|
media:
|
||||||
- type: image
|
- type: image
|
||||||
src: ./_assets/decla-red.jpg
|
src: ./_assets/decla-red.jpg
|
||||||
|
|
@ -26,7 +24,6 @@ article:
|
||||||
caption: Two teams, small planets, real gravity. The renderer underneath is the SDF-2D library from my thesis.
|
caption: Two teams, small planets, real gravity. The renderer underneath is the SDF-2D library from my thesis.
|
||||||
project:
|
project:
|
||||||
title: decla.red
|
title: decla.red
|
||||||
description: A multiplayer space shooter where client and server import the same rules package, the server ticks at 200 Hz, and the wire format is class names.
|
|
||||||
selected: true
|
selected: true
|
||||||
technologies: ['TypeScript', 'Node.js', 'WebSockets', 'WebGL']
|
technologies: ['TypeScript', 'Node.js', 'WebSockets', 'WebGL']
|
||||||
thumbnail:
|
thumbnail:
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,11 @@ links:
|
||||||
url: https://home.schmelczer.dev/git/andras/fizika
|
url: https://home.schmelczer.dev/git/andras/fizika
|
||||||
article:
|
article:
|
||||||
tags: ['web', 'tools']
|
tags: ['web', 'tools']
|
||||||
role: Question database, frontend, backend
|
|
||||||
stack: ['jQuery', 'vanilla HTML/CSS', 'Node/Express', 'JSON', 'localStorage']
|
stack: ['jQuery', 'vanilla HTML/CSS', 'Node/Express', 'JSON', 'localStorage']
|
||||||
outcome: A free practice app real students still find when they search for past érettségi physics papers
|
outcome: A free practice app real students still find when they search for past érettségi physics papers
|
||||||
audience: general
|
|
||||||
project:
|
project:
|
||||||
title: Fizika
|
title: Fizika
|
||||||
description: 'I needed it for my own physics érettségi: 682 past-paper questions, jQuery, localStorage, no accounts. Eight years on, students still find it.'
|
|
||||||
technologies: ['jQuery', 'HTML/CSS', 'Node/Express', 'JSON', 'localStorage']
|
technologies: ['jQuery', 'HTML/CSS', 'Node/Express', 'JSON', 'localStorage']
|
||||||
thumbnail:
|
|
||||||
alt: Screenshot of the Fizika practice app showing topic-selection buttons.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
I needed it. In my last year of high school I was about to sit the advanced-level (_emelt szintű_) physics érettségi, and the practice material I could find online was either paywalled or scattered across PDFs that wouldn't tell you whether your answer was right. So one evening in 2017 I started typing past exam questions into a JSON file.
|
I needed it. In my last year of high school I was about to sit the advanced-level (_emelt szintű_) physics érettségi, and the practice material I could find online was either paywalled or scattered across PDFs that wouldn't tell you whether your answer was right. So one evening in 2017 I started typing past exam questions into a JSON file.
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,9 @@ links:
|
||||||
article:
|
article:
|
||||||
iframeThumbnail: true
|
iframeThumbnail: true
|
||||||
tags: ['graphics', 'simulation', 'web']
|
tags: ['graphics', 'simulation', 'web']
|
||||||
role: Graphics and shader author
|
|
||||||
stack: ['TypeScript', 'WebGPU', 'WGSL', 'Compute shaders', 'Vite', 'Tweakpane']
|
stack: ['TypeScript', 'WebGPU', 'WGSL', 'Compute shaders', 'Vite', 'Tweakpane']
|
||||||
scale: One HTML file, 10 WGSL shaders, 6 vibe presets, up to 1.5M agents, 60 FPS target on consumer hardware
|
scale: One HTML file, 10 WGSL shaders, 6 vibe presets, up to 1.5M agents, 60 FPS target on consumer hardware
|
||||||
outcome: A browser drawing toy where user strokes seed an agent simulation that overwrites them
|
outcome: A browser drawing toy where user strokes seed an agent simulation that overwrites them
|
||||||
audience: technical
|
|
||||||
media:
|
media:
|
||||||
- type: image
|
- type: image
|
||||||
src: ./_assets/fleeting-garden.jpg
|
src: ./_assets/fleeting-garden.jpg
|
||||||
|
|
@ -26,7 +24,6 @@ article:
|
||||||
caption: A snapshot from one session. What you see is the trail texture; the agents that drew it are already gone.
|
caption: A snapshot from one session. What you see is the trail texture; the agents that drew it are already gone.
|
||||||
project:
|
project:
|
||||||
title: Fleeting Garden
|
title: Fleeting Garden
|
||||||
description: A single-file WebGPU drawing toy. Your strokes seed a swarm of up to a million agents; nine numbers per vibe give each preset its personality.
|
|
||||||
selected: true
|
selected: true
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ thumbnail:
|
||||||
alt: Chart comparing predicted and actual EUR/USD exchange rates.
|
alt: Chart comparing predicted and actual EUR/USD exchange rates.
|
||||||
article:
|
article:
|
||||||
tags: ['systems', 'tools']
|
tags: ['systems', 'tools']
|
||||||
role: Experiment author
|
|
||||||
stack: ['Python', 'NumPy', 'SciPy', 'Flask', 'MQL4']
|
stack: ['Python', 'NumPy', 'SciPy', 'Flask', 'MQL4']
|
||||||
outcome: A prediction server, an MQL4 trading client, and a clearer view of how far my edge wasn't
|
outcome: A prediction server, an MQL4 trading client, and a clearer view of how far my edge wasn't
|
||||||
audience: technical
|
|
||||||
project:
|
project:
|
||||||
title: Foreign Exchange Prediction Experiment
|
title: Foreign Exchange Prediction Experiment
|
||||||
description: A Hanning-windowed STFT experiment on EUR/USD. Passable backtest, sober conclusions, no real money risked.
|
|
||||||
thumbnail:
|
|
||||||
alt: Chart from a foreign exchange prediction experiment.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
In the autumn of 2019 I was an undergrad with a few free weekends and the quiet conviction that I could find a small edge on EUR/USD. The screenshots that survive are flattering: the predicted rate in blue hugging the actual rate in green closely enough to look like skill. It was a linear extrapolation in the frequency domain wearing a nice coat.
|
In the autumn of 2019 I was an undergrad with a few free weekends and the quiet conviction that I could find a small edge on EUR/USD. The screenshots that survive are flattering: the predicted rate in blue hugging the actual rate in green closely enough to look like skill. It was a linear extrapolation in the frequency domain wearing a nice coat.
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ links:
|
||||||
url: https://home.schmelczer.dev/git/andras/frame
|
url: https://home.schmelczer.dev/git/andras/frame
|
||||||
article:
|
article:
|
||||||
tags: ['embedded', 'systems', 'tools']
|
tags: ['embedded', 'systems', 'tools']
|
||||||
role: Frame builder and pipeline author
|
|
||||||
stack:
|
stack:
|
||||||
[
|
[
|
||||||
'Python',
|
'Python',
|
||||||
|
|
@ -24,7 +23,6 @@ article:
|
||||||
]
|
]
|
||||||
scale: One panel, one household, ~64 refreshes a day at peak
|
scale: One panel, one household, ~64 refreshes a day at peak
|
||||||
outcome: A wall-mounted photo frame that pulls from self-hosted Immich, gated on home presence, with no cloud dependencies
|
outcome: A wall-mounted photo frame that pulls from self-hosted Immich, gated on home presence, with no cloud dependencies
|
||||||
audience: general
|
|
||||||
media:
|
media:
|
||||||
- type: image
|
- type: image
|
||||||
src: ./_assets/frame.jpg
|
src: ./_assets/frame.jpg
|
||||||
|
|
@ -32,7 +30,6 @@ article:
|
||||||
caption: The bottom corners carry the photo's age and EXIF location. Painted as text on top, so the dither can't smear them.
|
caption: The bottom corners carry the photo's age and EXIF location. Painted as text on top, so the dither can't smear them.
|
||||||
project:
|
project:
|
||||||
title: Frame
|
title: Frame
|
||||||
description: A LAN-only e-ink photo frame. Pulls from self-hosted Immich, gated on Home Assistant presence, Atkinson-dithered to 6 colours, no cloud.
|
|
||||||
selected: true
|
selected: true
|
||||||
technologies:
|
technologies:
|
||||||
[
|
[
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
---
|
|
||||||
title: A JavaFX Editor for the Cooling Simulator
|
|
||||||
description: Companion editor for the cooling-system sim. Drag-and-drop plant layout, JSON export, upload-to-backend. The smallest tool, and the one the event leaned on.
|
|
||||||
date: 2026-04-25
|
|
||||||
period: 'October-November 2018'
|
|
||||||
thumbnail:
|
|
||||||
src: ./_assets/process-simulator-input.jpg
|
|
||||||
alt: JavaFX graph editor for the cooling system simulator.
|
|
||||||
article:
|
|
||||||
tags: ['simulation', 'tools']
|
|
||||||
role: Editor author
|
|
||||||
stack: ['JavaFX', 'JSON', 'REST API']
|
|
||||||
outcome: A drag-and-drop graph editor that let non-developers feed the simulator
|
|
||||||
audience: technical
|
|
||||||
project:
|
|
||||||
title: Graph Editor
|
|
||||||
description: A drag-and-drop JavaFX editor that let event organisers reconfigure the cooling sim without me sitting next to them.
|
|
||||||
thumbnail:
|
|
||||||
alt: JavaFX editor interface for the cooling system simulator input graph.
|
|
||||||
---
|
|
||||||
|
|
||||||
The brief was one sentence: non-technical event organisers needed to rewire a simulated cooling plant, live, without me hovering behind them. That sentence quietly ruled out every interface I would have enjoyed building: config files, a DSL, anything with a curly brace in it. The [cooling-system sim](/articles/nuclear-cooling-simulation/) was only going to be as useful as the tool that fed it, so in late 2018 I built a JavaFX desktop editor: lay the plant out as a graph, drag pipes between pumps and coolers, tune each element's parameters in a side panel, then export JSON or upload it straight to the backend.
|
|
||||||
|
|
||||||
It was the smallest piece of the whole project and the piece the event quietly depended on. A simulator only its author can reconfigure is a demo; the editor is what made it a tool other people could own for a weekend.
|
|
||||||
|
|
||||||
If I built it again I'd skip JavaFX and put the editor in the browser, next to the monitoring clients. Cross-platform desktop packaging was a fight, and every install I asked of the organisers was one more reason for them to call me over, which was the exact thing the brief said to prevent.
|
|
||||||
|
|
@ -17,11 +17,9 @@ links:
|
||||||
article:
|
article:
|
||||||
featuredOrder: 1
|
featuredOrder: 1
|
||||||
tags: ['ai', 'systems', 'tools']
|
tags: ['ai', 'systems', 'tools']
|
||||||
role: Researcher and framework author
|
|
||||||
stack: ['Python', 'decorators', 'FastAPI', 'survey design']
|
stack: ['Python', 'decorators', 'FastAPI', 'survey design']
|
||||||
scale: 33 deployment habits surveyed, 6 proposed additions, framework evaluated by working data scientists and engineers
|
scale: 33 deployment habits surveyed, 6 proposed additions, framework evaluated by working data scientists and engineers
|
||||||
outcome: A pip-installable framework, an MSc thesis, and one strong opinion about API surface area
|
outcome: A pip-installable framework, an MSc thesis, and one strong opinion about API surface area
|
||||||
audience: recruiter-relevant
|
|
||||||
media:
|
media:
|
||||||
- type: image
|
- type: image
|
||||||
src: ./_assets/great-ai.png
|
src: ./_assets/great-ai.png
|
||||||
|
|
@ -29,7 +27,6 @@ article:
|
||||||
caption: A working GreatAI service is about ten lines on top of a plain prediction function.
|
caption: A working GreatAI service is about ten lines on top of a plain prediction function.
|
||||||
project:
|
project:
|
||||||
title: GreatAI
|
title: GreatAI
|
||||||
description: One decorator on a Python function turned it into a deployed ML service. MSc thesis with a survey to back the API choices.
|
|
||||||
selected: true
|
selected: true
|
||||||
technologies: ['Python', 'ML deployment', 'API design']
|
technologies: ['Python', 'ML deployment', 'API design']
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,9 @@ links:
|
||||||
article:
|
article:
|
||||||
featuredOrder: 4
|
featuredOrder: 4
|
||||||
tags: ['systems', 'web', 'tools']
|
tags: ['systems', 'web', 'tools']
|
||||||
role: Full-stack author
|
|
||||||
stack: ['Python', 'Angular', 'TypeScript', 'FastAPI', 'SQLite']
|
stack: ['Python', 'Angular', 'TypeScript', 'FastAPI', 'SQLite']
|
||||||
scale: Multi-device goal and task state shared between clients and a server
|
scale: Multi-device goal and task state shared between clients and a server
|
||||||
outcome: A goal tracker still in use, and a lesson about when clever sync isn't worth it
|
outcome: A goal tracker still in use, and a lesson about when clever sync isn't worth it
|
||||||
audience: recruiter-relevant
|
|
||||||
media:
|
media:
|
||||||
- type: image
|
- type: image
|
||||||
src: ./_assets/towers.jpg
|
src: ./_assets/towers.jpg
|
||||||
|
|
@ -24,7 +22,6 @@ article:
|
||||||
caption: Towers of finished tasks, one column per goal. Done blocks fall into place with a small gravity animation.
|
caption: Towers of finished tasks, one column per goal. Done blocks fall into place with a small gravity animation.
|
||||||
project:
|
project:
|
||||||
title: Life Towers
|
title: Life Towers
|
||||||
description: A multi-device goal tracker where the clever trie lost to send-the-whole-tree with a version counter. The towers were the UI; the protocol was the lesson.
|
|
||||||
selected: true
|
selected: true
|
||||||
technologies: ['Python', 'Angular', 'TypeScript', 'Immutable trees']
|
technologies: ['Python', 'Angular', 'TypeScript', 'Immutable trees']
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ thumbnail:
|
||||||
alt: RGB LED strips lit by a music synchronisation project.
|
alt: RGB LED strips lit by a music synchronisation project.
|
||||||
article:
|
article:
|
||||||
tags: ['systems', 'tools']
|
tags: ['systems', 'tools']
|
||||||
role: Hardware and software author
|
|
||||||
stack: ['Python', 'NumPy', 'FFT', 'Raspberry Pi', 'MOSFETs', 'vanilla web']
|
stack: ['Python', 'NumPy', 'FFT', 'Raspberry Pi', 'MOSFETs', 'vanilla web']
|
||||||
outcome: The first non-trivial project I started and finished
|
outcome: The first non-trivial project I started and finished
|
||||||
audience: technical
|
|
||||||
project:
|
project:
|
||||||
title: Lights Synchronized to Music
|
title: Lights Synchronized to Music
|
||||||
description: Raspberry Pi music player, NumPy FFT, MOSFETs, RGB strips. The first thing I built that I actually finished.
|
|
||||||
thumbnail:
|
|
||||||
alt: RGB LED strips glowing from a music synchronization project.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Spring 2016. I had a Raspberry Pi, a couple of 12V RGB LED strips someone had given me, a handful of MOSFETs from an electronics kit, and no idea what I was doing. I wired one of the MOSFETs backwards and it got hot enough to leave a small mark on the breadboard, which is how I learned, slowly and because I had to, to read a datasheet. This was the first thing I ever started and actually finished.
|
Spring 2016. I had a Raspberry Pi, a couple of 12V RGB LED strips someone had given me, a handful of MOSFETs from an electronics kit, and no idea what I was doing. I wired one of the MOSFETs backwards and it got hot enough to leave a small mark on the breadboard, which is how I learned, slowly and because I had to, to read a datasheet. This was the first thing I ever started and actually finished.
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,9 @@ thumbnail:
|
||||||
article:
|
article:
|
||||||
featuredOrder: 5
|
featuredOrder: 5
|
||||||
tags: ['simulation', 'systems', 'tools']
|
tags: ['simulation', 'systems', 'tools']
|
||||||
role: Simulation and UI author
|
|
||||||
stack: ['Python', 'Flask', 'NumPy', 'HTML canvas', 'JavaFX']
|
stack: ['Python', 'Flask', 'NumPy', 'HTML canvas', 'JavaFX']
|
||||||
scale: One remote sim server, many monitoring clients, separate JavaFX graph editor
|
scale: One remote sim server, many monitoring clients, separate JavaFX graph editor
|
||||||
outcome: A believable PLC simulation usable by non-specialists during a live cybersecurity challenge
|
outcome: A believable PLC simulation usable by non-specialists during a live cybersecurity challenge
|
||||||
audience: recruiter-relevant
|
|
||||||
media:
|
media:
|
||||||
- type: image
|
- type: image
|
||||||
src: ./_assets/process-simulator.jpg
|
src: ./_assets/process-simulator.jpg
|
||||||
|
|
@ -25,7 +23,6 @@ article:
|
||||||
caption: The JavaFX editor produced JSON that the simulator ate as input.
|
caption: The JavaFX editor produced JSON that the simulator ate as input.
|
||||||
project:
|
project:
|
||||||
title: Cooling System Simulation
|
title: Cooling System Simulation
|
||||||
description: 'A live cooling-plant simulator for a PLC cybersecurity event. Flow as graph traversal and heat as a matrix solve: two passes instead of one PDE.'
|
|
||||||
selected: true
|
selected: true
|
||||||
thumbnail:
|
thumbnail:
|
||||||
src: ./_assets/nuclear-simulation.jpg
|
src: ./_assets/nuclear-simulation.jpg
|
||||||
|
|
@ -48,10 +45,12 @@ As physics, this is wrong; flow and heat are coupled, and a real plant knows it.
|
||||||
|
|
||||||
## The editor mattered more than the solver
|
## The editor mattered more than the solver
|
||||||
|
|
||||||
The most-used interface in the whole system was the input editor, a separate JavaFX tool where organisers laid out the plant, parameterised each element, and exported the JSON the sim consumed. It earned [its own write-up](/articles/graph-editor-javafx-simulation-input/), because in hindsight it was its own project: the simulator decided what was possible, but the editor decided who could use it.
|
The brief for the editor was one sentence: non-technical organisers needed to rewire the plant, live, without me hovering behind them. That quietly ruled out every interface I'd have enjoyed building, namely config files, a DSL, anything with a curly brace in it. So the most-used piece of the whole system ended up being a separate JavaFX desktop tool where organisers laid the plant out as a graph, dragged pipes between pumps and coolers, tuned each element's parameters in a side panel, and exported the JSON the sim consumed, or uploaded it straight to the backend.
|
||||||
|
|
||||||
|
It was the smallest piece of the project and the one the event quietly depended on. A simulator only its author can reconfigure is a demo; the editor is what made it a tool other people could own for a weekend. The simulator decided what was possible, but the editor decided who could use it.
|
||||||
|
|
||||||
## What I'd change
|
## What I'd change
|
||||||
|
|
||||||
- **State what the model claims.** A convincing simulator owes its audience an honest README about what it does and doesn't capture. Mine didn't have one, and anyone who took the numbers seriously could have walked away believing more than the model deserved.
|
- **State what the model claims.** A convincing simulator owes its audience an honest README about what it does and doesn't capture. Mine didn't have one, and anyone who took the numbers seriously could have walked away believing more than the model deserved.
|
||||||
- **Recorded scenarios as regression tests.** Simulations drift in ways that still look plausible on screen. A few stored "this input over 60 seconds produces these outputs" runs would have caught me when I broke the temperature solver, which I did on the Saturday morning of the event, naturally.
|
- **Recorded scenarios as regression tests.** Simulations drift in ways that still look plausible on screen. A few stored "this input over 60 seconds produces these outputs" runs would have caught me when I broke the temperature solver, which I did on the Saturday morning of the event, naturally.
|
||||||
- **Skip JavaFX.** Cross-platform packaging was a fight, and a web editor living next to the monitoring clients would have meant one fewer install for everyone.
|
- **Skip JavaFX.** Cross-platform desktop packaging was a fight, and every install I asked of the organisers was one more reason to call me over, which is the exact thing the brief said to prevent. A web editor living next to the monitoring clients would have meant one fewer install for everyone.
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ links:
|
||||||
url: https://perfect-postcode.co.uk
|
url: https://perfect-postcode.co.uk
|
||||||
article:
|
article:
|
||||||
tags: ['systems', 'web', 'tools']
|
tags: ['systems', 'web', 'tools']
|
||||||
role: Server architect and operator
|
|
||||||
stack:
|
stack:
|
||||||
[
|
[
|
||||||
'Rust',
|
'Rust',
|
||||||
|
|
@ -28,7 +27,6 @@ article:
|
||||||
]
|
]
|
||||||
scale: ~25M historical properties, ~2.5M postcodes, ~150 numeric features per row, all in RAM on a single VM
|
scale: ~25M historical properties, ~2.5M postcodes, ~150 numeric features per row, all in RAM on a single VM
|
||||||
outcome: A single-binary UK property-intelligence service with sub-100ms hexagon aggregations under filter
|
outcome: A single-binary UK property-intelligence service with sub-100ms hexagon aggregations under filter
|
||||||
audience: technical
|
|
||||||
media:
|
media:
|
||||||
- type: image
|
- type: image
|
||||||
src: ./_assets/perfect-postcode.jpg
|
src: ./_assets/perfect-postcode.jpg
|
||||||
|
|
@ -36,10 +34,7 @@ article:
|
||||||
caption: A normal user pan triggers a hexagon aggregation under filter. The hot path holds itself to three integer compares per row.
|
caption: A normal user pan triggers a hexagon aggregation under filter. The hot path holds itself to three integer compares per row.
|
||||||
project:
|
project:
|
||||||
title: Perfect Postcode
|
title: Perfect Postcode
|
||||||
description: A UK property-intelligence map. ~25M historical transactions, ~150 features per row, all u16-quantised in RAM, served from a single Rust binary.
|
|
||||||
selected: true
|
selected: true
|
||||||
thumbnail:
|
|
||||||
alt: The Perfect Postcode dashboard with active filters on property type, price, transit time, and crime, showing a Manchester map with matching properties as a heatmap.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
A user told me the map felt sluggish when they dragged it across Manchester with four filters on. They were right, and it stung, because the previous version round-tripped to a database, decoded floats, and had spent its entire latency budget before it finished evaluating the first filter. The rewrite is one Rust binary that holds the entire UK property history in RAM and treats every filter as three integer compares. Everything else in this post follows from refusing to let that sluggishness come back.
|
A user told me the map felt sluggish when they dragged it across Manchester with four filters on. They were right, and it stung, because the previous version round-tripped to a database, decoded floats, and had spent its entire latency budget before it finished evaluating the first filter. The rewrite is one Rust binary that holds the entire UK property history in RAM and treats every filter as three integer compares. Everything else in this post follows from refusing to let that sluggishness come back.
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,10 @@ thumbnail:
|
||||||
alt: Screenshot of a generated photography site.
|
alt: Screenshot of a generated photography site.
|
||||||
article:
|
article:
|
||||||
tags: ['web', 'tools']
|
tags: ['web', 'tools']
|
||||||
role: Site generator author
|
|
||||||
stack: ['Webpack', 'Vite', 'TypeScript', 'Image processing']
|
stack: ['Webpack', 'Vite', 'TypeScript', 'Image processing']
|
||||||
outcome: A photography site that updates itself when I drop new images into a folder
|
outcome: A photography site that updates itself when I drop new images into a folder
|
||||||
audience: general
|
|
||||||
project:
|
project:
|
||||||
title: Photo Site Generator
|
title: Photo Site Generator
|
||||||
description: Point a build script at a folder of photos, get a static site with responsive image variants. An excuse to walk with a camera.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
I take walks with a camera. Most of what I shoot isn't good, but walking slowly with a frame to think about is the most reliable way I know to come back with an idea for whatever I'm actually working on. In the summer of 2016 I wanted somewhere to put the few frames that survived, and I wasn't going to run a CMS for it. So: a Webpack script. Point it at a directory of full-size photos, get a static site with responsive variants of each. Drop a photo in, build, deploy.
|
I take walks with a camera. Most of what I shoot isn't good, but walking slowly with a frame to think about is the most reliable way I know to come back with an idea for whatever I'm actually working on. In the summer of 2016 I wanted somewhere to put the few frames that survived, and I wasn't going to run a CMS for it. So: a Webpack script. Point it at a directory of full-size photos, get a static site with responsive variants of each. Drop a photo in, build, deploy.
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,10 @@ thumbnail:
|
||||||
alt: Screenshot from a 3D platform game written in C.
|
alt: Screenshot from a 3D platform game written in C.
|
||||||
article:
|
article:
|
||||||
tags: ['games', 'systems']
|
tags: ['games', 'systems']
|
||||||
role: Game author
|
|
||||||
stack: ['C', 'SDL 1.2', 'Voxel terrain']
|
stack: ['C', 'SDL 1.2', 'Voxel terrain']
|
||||||
outcome: A playable course project, and the moment programming clicked
|
outcome: A playable course project, and the moment programming clicked
|
||||||
audience: technical
|
|
||||||
project:
|
project:
|
||||||
title: Platform Game
|
title: Platform Game
|
||||||
description: My Basics of Programming project. 3D voxel game in C and SDL 1.2. Pointers, learned painfully.
|
|
||||||
thumbnail:
|
|
||||||
alt: Screenshot from an early 3D platform game.
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Autumn 2017, first semester, a course called Basics of Programming, and a free-choice project I aimed far too high on: a 3D voxel platformer in pure C with SDL 1.2. No engine, no scripting layer, no one to tell me that "3D in software, in C, in your first semester" was an unusual reading of the assignment.
|
Autumn 2017, first semester, a course called Basics of Programming, and a free-choice project I aimed far too high on: a 3D voxel platformer in pure C with SDL 1.2. No engine, no scripting layer, no one to tell me that "3D in software, in C, in your first semester" was an unusual reading of the assignment.
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,9 @@ links:
|
||||||
article:
|
article:
|
||||||
featuredOrder: 2
|
featuredOrder: 2
|
||||||
tags: ['systems', 'tools', 'web']
|
tags: ['systems', 'tools', 'web']
|
||||||
role: Library author
|
|
||||||
stack: ['Rust', 'WebAssembly', 'Python', 'pyo3', 'wasm-bindgen']
|
stack: ['Rust', 'WebAssembly', 'Python', 'pyo3', 'wasm-bindgen']
|
||||||
scale: One Rust core, three published packages (crates.io, npm, PyPI), driving an Obsidian sync plugin
|
scale: One Rust core, three published packages (crates.io, npm, PyPI), driving an Obsidian sync plugin
|
||||||
outcome: A small Rust library that auto-resolves prose conflicts, with WASM and Python bindings
|
outcome: A small Rust library that auto-resolves prose conflicts, with WASM and Python bindings
|
||||||
audience: recruiter-relevant
|
|
||||||
media:
|
media:
|
||||||
- type: image
|
- type: image
|
||||||
src: ./_assets/reconcile.png
|
src: ./_assets/reconcile.png
|
||||||
|
|
@ -32,7 +30,6 @@ article:
|
||||||
caption: reconcile-text weaves conflicting edits together instead of asking a human to choose.
|
caption: reconcile-text weaves conflicting edits together instead of asking a human to choose.
|
||||||
project:
|
project:
|
||||||
title: reconcile-text
|
title: reconcile-text
|
||||||
description: One Rust core, three packages. Merges Markdown notes from three editors I don't control, with no operation history. Never emits markers.
|
|
||||||
selected: true
|
selected: true
|
||||||
technologies: ['Rust', 'WebAssembly', 'Python', 'pyo3', 'wasm-bindgen', 'Myers diff']
|
technologies: ['Rust', 'WebAssembly', 'Python', 'pyo3', 'wasm-bindgen', 'Myers diff']
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ links:
|
||||||
article:
|
article:
|
||||||
featuredOrder: 3
|
featuredOrder: 3
|
||||||
tags: ['graphics', 'web', 'systems']
|
tags: ['graphics', 'web', 'systems']
|
||||||
role: Library author
|
|
||||||
stack:
|
stack:
|
||||||
[
|
[
|
||||||
'TypeScript',
|
'TypeScript',
|
||||||
|
|
@ -28,7 +27,6 @@ article:
|
||||||
]
|
]
|
||||||
scale: Browser library, mobile-targeted, real-time on consumer GPUs, both WebGL1 and WebGL2 paths
|
scale: Browser library, mobile-targeted, real-time on consumer GPUs, both WebGL1 and WebGL2 paths
|
||||||
outcome: An NPM package and BSc thesis; the renderer behind the decla.red multiplayer game
|
outcome: An NPM package and BSc thesis; the renderer behind the decla.red multiplayer game
|
||||||
audience: recruiter-relevant
|
|
||||||
media:
|
media:
|
||||||
- type: image
|
- type: image
|
||||||
src: ./_assets/sdf2d.jpg
|
src: ./_assets/sdf2d.jpg
|
||||||
|
|
@ -36,7 +34,6 @@ article:
|
||||||
caption: SDF-2D shipped as a TypeScript library, not a one-shot demo. That distinction shaped most of the design.
|
caption: SDF-2D shipped as a TypeScript library, not a one-shot demo. That distinction shaped most of the design.
|
||||||
project:
|
project:
|
||||||
title: SDF-2D
|
title: SDF-2D
|
||||||
description: A browser 2D ray-tracer tuned for the phone in your pocket. Tile-based passes, deferred shading, shaders generated per scene and device.
|
|
||||||
selected: true
|
selected: true
|
||||||
technologies: ['TypeScript', 'WebGL', 'WebGL2', 'Signed distance fields']
|
technologies: ['TypeScript', 'WebGL', 'WebGL2', 'Signed distance fields']
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ links:
|
||||||
url: https://vault-link.schmelczer.dev
|
url: https://vault-link.schmelczer.dev
|
||||||
article:
|
article:
|
||||||
tags: ['systems', 'web', 'tools']
|
tags: ['systems', 'web', 'tools']
|
||||||
role: Sync engine and server author
|
|
||||||
stack:
|
stack:
|
||||||
[
|
[
|
||||||
'Rust',
|
'Rust',
|
||||||
|
|
@ -29,10 +28,8 @@ article:
|
||||||
]
|
]
|
||||||
scale: One Rust server, one TypeScript sync engine, three published consumers (Obsidian plugin, CLI, fuzz/deterministic test harnesses)
|
scale: One Rust server, one TypeScript sync engine, three published consumers (Obsidian plugin, CLI, fuzz/deterministic test harnesses)
|
||||||
outcome: A self-hosted Obsidian sync I trust enough to use as my primary vault transport
|
outcome: A self-hosted Obsidian sync I trust enough to use as my primary vault transport
|
||||||
audience: technical
|
|
||||||
project:
|
project:
|
||||||
title: VaultLink
|
title: VaultLink
|
||||||
description: 'I refuse to give up the editor: Obsidian, Vim, VS Code, sed. Self-hosted sync that survives all four, built on reconcile-text underneath.'
|
|
||||||
selected: true
|
selected: true
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue