← Work
PERSONAL PROJECT 2026/05 → 2026/05

Australian Inactive Housing Map

Official government spatial datasets are often locked behind sluggish, academic dashboards that fail to provide immediate local feedback. I built this interactive, instant-load WebGL mapping dashboard to demonstrate how we can better visualise ABS vacancy datasets for everyday users.

View the Demo →

The Origin

This project was born out of a desire to build a more responsive, interactive spatial visualization tool than the standard resources provided by the government.

After attending a lecture on housing statistics, I began looking into the official numbers compiled by the Australian Bureau of Statistics (ABS). I found that the ABS does provide a map—specifically an ArcGIS-based storymap—but the visualiser was sluggish to navigate, lacked immediate local feedback, and felt a little too academic.

I wanted an excuse to experiment with client-side WebGL mapping engines and responsive visual states. The goal was to build a lightweight, standalone client application that could load large spatial boundaries instantly and let users query their local area, then estimate a human cost.

Key Engineering Decisions

Rather than building a standard database-driven web application, the project was structured around three specific architectural decisions to optimise speed and data clarity.

1. Zero-API Static Ingestion (Local Data)

Instead of querying slow external government ArcGIS servers at runtime—which introduces network latency and CORS complications—the application operates on a Zero-API architecture.

All geographic boundary shapes and statistics are pre-compiled and bundled directly as local JSON/GeoJSON files. By pre-simplifying high-density polygons using the Visvalingam-Whyatt algorithm, I compressed over 540 Councils and 2,300 Suburbs into a single client-side asset under 5MB that parses instantly. Largely done because I felt a larger download footprint was significantly less noticeable than a 5-15 second compiling delay on page load.

Data is cheap, but phones are slow

2. Multi-Mode Leaderboards & Urban-Only Filtering

Comparing metropolitan cities directly against small holiday towns on a single vacancy rate index produces skewed results (e.g., a tiny holiday village showing 25% vacancy but only 50 units, versus a major city showing 1.5% vacancy but representing thousands of empty homes).

To make the comparisons meaningful, I designed a multi-mode sorting dashboard in the sidebar:

  • By Volume: Sorts by the absolute count of empty dwellings to highlight high-density areas where vacancy volume is greatest.
  • By Percentage: Sorts by raw vacancy rate to highlight regional spec-holding hubs.
  • By State Aggregate: Dynamically rolls up all active councils to highlight regional/jurisdictional trends.
  • The "Urban Only" Toggle: Filters out small regional/holiday communities by isolating councils with ≥ 15,000 dwellings, focusing analytical attention on areas experiencing high-density rental and buying stress.

3. Humanising the Numbers (Household Size Multipliers)

Raw vacancy percentages (e.g., "1.3%") feel highly abstract. To ground these numbers in real terms, the dashboard sidebar translates counts into housing capacity using a straightforward multiplier:

Displaced People = Inactive Dwellings × Average Household Size

By mapping average household size constants derived from local Census data for each individual council area, the map estimates exactly how many people could be accommodated. In Salisbury Council, a multi-agency MADIP indicator identifies 267 inactive dwellings. Multiplied against the local constant of 2.66 persons per household, it outputs a capacity of 710 displaced people, humanising a dry statistic.

Calculations & Testing Precision

To ensure the AI didn't get bored and wander, I integrated automated unit tests early on to validate calculations across varying data subsets.

Smart Meter Denominator Correction

A mistake the AI loved to make was multiplying the electricity inactivity percentage against the council's Total Dwellings. In councils with lower smart-meter coverage, this overstates empty units by up to 27%.

// Example Salisbury Council Math
Total Dwellings = 56,759
Dwellings with smart meter data = 44,693
Electricity Inactivity rate = 1.3%

✕ Naive count: 56,759 × 1.3% = 738 empty homes
✓ Correct count: 44,693 × 1.3% = 581 empty homes

AI Workflow Series — Part 01

The Spec is the Product

In a post-AI world, the idea and the code for a project like this is valueless; only the spec holds value.

This project was built as an AI-led implementation experiment, with human-authored spec and review gates. Gemini 3 Flash acted as an enthusiastic (if a bit dim) coworker. I usually write high performance C++ or C, so this project was an experiment in delegating the implementation layer entirely. The unit tests were an absolute must, as was providing a way to test the UI/UX with Playwright.

My core philosophy is to treat the AI similarly to how I work with human juniors, but driven through a series of markdown files. A robust spec for this workflow needs four distinct components:

  • Goal & Intent: The soft goal of the work: why we want to make it, and for whom.
  • Scope & Specification: What it is, what it isn't, and how it should work and feel.
  • UI/UX: General tone and feel, as well as detailing out specific components. With the caveat that if I don't detail it, it's not important to me, which I left entirely up to the AI to decide.
  • Implementation Details: Architecture, coding principles, libraries to use, and deployment strategy.

With the spec defined, I let an AI agent break those down into an implementation plan, ensuring there were clear stages where I could manually review progress and direction. The process ended up more iterative than I planned—the spec needed more detail upfront.

One key finding: AI has a predilection to agree with the user too much. I regularly had to instruct it to be antagonistic towards me, or pretend I didn't write the spec, just so it would criticise the design fairly.