mjdc.io Get in touch →

Things I’ve built

Selected projects

Predicting World Cup results, poorly.

Ran live at World Cup 2026

Elo ratings built from every men’s international since 1872, plus a model that turns rating gaps into match odds. It ran live at ballonpoor.com for the last 19 games of the 2026 World Cup. The bookies won the group stage. The model called three of the five knockout ties where they disagreed.

  • Python
  • JavaScript
  • Cloudflare
ballonpoor.comRecorded Oct 2026
The live site after the final whistle: the whole knockout draw, then a quarter-final’s score, scorers and stats.

Ballon p’Oor / the engine

Who’s the best team in the world? Depends on the day.

I replayed every men’s international since 1872 through the same Elo engine that ran my World Cup site. Nineteen countries have been number one, and the 2026 final was #2 beating #1 to take it.

Nineteen countries have been rated the best team in the world since 1883, when a team first had the 20 matches needed to qualify. Brazil has held number one longest, 36.8 years in total, then England (27.7), Scotland (15.6) and Argentina (13.0). The 2026 World Cup final was #1 Argentina (2,245) against #2 Spain (2,233). Spain won 1–0 after extra time and is still number one.

Total time rated world number one, March 1883 to October 2026
NationYears at #1Separate spellsLongest spell
Brazil36.859Apr 1995 to Jul 2000
England27.729Apr 1891 to May 1902
Scotland15.612Mar 1883 to Apr 1891
Argentina13.043Jan 1941 to Jul 1943
Italy11.216Oct 1934 to Feb 1940
Hungary8.513Jun 1918 to Apr 1921
Germany (incl. West Germany)8.022Mar 1993 to Jul 1994
Netherlands4.810May 1915 to Oct 1917
USSR / Russia4.616Apr 1963 to Oct 1964
Spain4.111Jun 2012 to Jun 2013
Austria3.25Sep 1931 to Oct 1933
France3.110Jul 2000 to May 2002
Czechoslovakia1.87Sep 1927 to Jun 1928
Uruguay1.12Jun 1924 to Apr 1925
Mexico54 days1Mar to May 1990
Belgium36 days2Sep to Oct 2020
Denmark14 days1Jun 1918
Sweden6 days1Jun 1988
Czech Republic4 days1Jun 2005

Men’s internationals, 1872–Oct 2026. POOR Elo ratings. #1 needs 20 matches, one of them in the last four years. Ratings drift up as more teams join, so compare within an era. Before 1900 it’s mostly four British teams playing each other.

There’s a lot hiding in a climb time.

Live at poursuivant.cc

Estimated climbing power for pro cycling. Where nobody hand-timed a climb, the time gets pieced back together from gap reports, kilometre splits and physics, then turned into watts per kilo with the assumptions left showing. Climbs too short or too shallow for the physics never make it out.

  • Python
  • Astro
  • Physics
poursuivant.ccRecorded Oct 2026
The live site: a stage profile, estimated watts per kilo with their error bands, and the Alpe d’Huez archive.

Poursuivant / Hautacam, Tour de France 2025

The race data had no clock.

In the archived race tickers, 683 of 684 events are timestamped zero. So Poursuivant rebuilds each climb from gap reports, finish times and physics, then checks itself against times clocked off the TV.

The ticker’s events on this climb are all stamped 00:00. Rebuilt from gap reports and Pogačar’s kilometre splits, his 35:07 climb comes out at 35:17, ten seconds out. Across the nine riders below the median miss is 27 seconds; across 47 hand-timed summit-finish times it’s 69.

    Hautacam, foot to summit: hand-timed against rebuilt
    RiderHand-timedRebuiltMiss
    Pogačar35:0735:17+10 s
    Vingegaard37:1737:44+27 s
    Lipowitz37:3037:41+11 s
    Johannessen38:0736:58−69 s
    Onley38:0736:58−69 s
    Vauquelin38:4037:38−62 s
    Evenepoel38:4237:38−64 s
    Gall39:0939:20+11 s
    Roglič39:1539:26+11 s

    Gaps and splits from public race reports; hand times from climbing-records.com; reconstruction by Poursuivant. Lines between reports are interpolated. Summit gaps assume the group hit the foot together.

    Every cent has to land somewhere.

    In development · private pilot

    Software for small NSW strata schemes run by their own committees: levies, the ledger, meetings and records. Levies get split by unit entitlement to the exact cent. Where AI reads a document, a figure only shows up if the words on the page actually say it.

    • TypeScript
    • PostgreSQL
    • AI extraction
    localhost · fictional demo dataDev build, Oct 2026
    A development build on made-up data: a fictional building’s next 90 days, its levies, then an Agreement Check report.

    Storey / levy maths

    The last cent is the hard one.

    Storey splits a strata levy between lots by unit entitlement, to the cent. Round each share and the bills don’t add up; hand out the spare cents fairly and, now and then, a bigger levy means someone pays less.

    Six fictional lots with unit entitlements of 15, 15, 17, 17, 18 and 18 (out of 100) share a quarterly levy. At $6,000.50, lots 1 to 4 each owe exactly half a cent on top of their whole cents, and there are only two spare cents. Ties go to the lower lot number, so lots 1 and 2 pay $900.08 and lots 3 and 4 pay $1,020.08.

    Raise the levy a cent, to $6,000.51, and lot 2’s bill falls to $900.07. Rounding each lot on its own would have billed $6,000.52 for the $6,000.50 levy.

    Fictional six-lot scheme from Storey’s tests, split by the app’s own allocation code.From $6,000.00 to $6,999.99, rounding each lot misses the total 61% of the time. A one-cent rise trips the paradox 1% of the time.

    A shop website the shop can maintain.

    Live at vanillacycles.com

    My local bike shop got hacked offline and quoted $20k for a rebuild, so I built a Shopify theme on Horizon instead, mostly over one weekend. There was almost no photography, so type, cream bands and one brand blue carry the pages. Nearly all the copy is an editor setting, so the shop can change it without me.

    vanillacycles.comRecorded Oct 2026
    The live store: the homepage, X-Lab and the service menu, with the phone version alongside.

    Vanilla Cycles / design for what you’ve got

    Photos optional.

    Most shop themes are built around big, beautiful photos. The shop didn’t have any, so I built a homepage that holds up without them.

    Shopify’s Horizon demo store

    65.5%photograph

    2.3%type and colour

    A full-bleed hero and eight product photos.

    Vanilla Cycles

    11.1%photograph

    84.7%type and colour

    Three photos, three striped placeholders. The rest is type and colour.

    Same width, different lengths: 1,926 px against 5,075 px. Vanilla’s page is 2.6× longer and still 85% type and colour.

    Measured cell by cell, Horizon’s demo homepage is mostly a full-bleed hero and eight product photos. Take them away and it’s 97.7% blank white. Vanilla’s homepage is cream and sand bands, ink, teal and big type, so when its three photos go, the slots fall back to stripes and the page still holds up.

    What each homepage is made of, share of cells
    Painted asHorizon demoVanilla Cycles
    Photograph65.5%11.1%
    Striped placeholder0%4.2%
    Type2.3%9.9%
    Colour band0%74.8%
    White32.2%0%

    Live homepages sampled on a 20px grid at 1440px wide, October 2026.Photos drawn as flat-tone mosaics, not the real images.

    Writing

    Occasionally I write up something from a recent side-quest.

    Project

    Building Ballon p’Oor

    I challenged myself to build a World Cup site with live scores, a bracket and a probability model behind it. The model took two days, the site took one. Here’s how I did it, and how it went.

    Also on the workbench: AFL and horse-racing ratings, a lecture player that transcribes itself, an AI morning briefing, and a half-built test of whether quoting the pesticide register beats a chatbot on farm questions.

    About me

    I like building stuff that solves real problems.

    Sometimes that’s just for me (see: the projects I talk about here), sometimes it’s working with crazy ambitious founders and leading large teams (see: Canva, Sonder), and sometimes it’s for big companies (see: New York Times, Commonwealth Bank of Australia). Before that I started an ad agency with some friends, briefly thought I’d be an academic, and was one of the earliest employees at NEXTDC (in the good old days when normal people barely knew what a data centre was).

    If you’re a dev in Australia, chances are you’ve seen my mug around when we re-launched the Canva developer ecosystem. If we haven’t met and you’d like to work together, get in touch.

    Where I’ve worked

    Sonder
    AI-enabled careGroup Product Manager · Current
    Woolworths
    Refresh:FoodFounding Head of Product
    Canva
    Developer ecosystemGroup Product Manager
    The New York Times
    Audio & growthProduct leadership
    Commonwealth Bank
    Everyday bankingSenior Product Manager

    Earlier: co-founding an agency, a brief detour towards academia, and joining NEXTDC in its early days.

    Contact

    Say hello.

    Drop a note below and I’ll get back to you.

    Your message
    All fields are required.