IkenaAI
IkenaAI · Field Notes · Behind the 3D
Engineering2026-05-087 min read

Behind the 3D: How We Mapped Every Honolulu Building Footprint with Real Heights

The Hawaii 3D map at ai.ikenagroup.com/3d renders every parcel statewide and every Honolulu building footprint with accurate extruded heights. It runs in a browser tab, no server-side tile rendering, no API keys. Here's how it's built — and why all 56 million lines of source data live in TypeScript.

384,262
Parcels statewide
239,458
Honolulu buildings w/ heights
204,775
Address points
~56M
Lines of TypeScript

The premise

Hawaii's parcel and building data is fully public. The State Office of Planning publishes statewide parcels via ArcGIS REST. Honolulu DPP publishes building footprints. The City & County publishes address points. None of these come pre-joined or pre-3D-extruded, and the official viewers (HoLIS, Hawaii GIS Program) are slow server-side renderers locked to per-county scopes.

The premise behind hawaii-as-code was: scrape the public data once, encode it as static TypeScript files, ship them behind a CDN, render the entire dataset in the browser. No database, no API key, no rate-limited tile server. The browser holds the whole island in memory.

Why TypeScript files, not Postgres

Counterintuitive choice. Most spatial projects start with PostGIS. A few reasons we went the other way:

The pipeline (rough sketch)

┌──────────────────────────────────────────────┐
│ 1. Scrape statewide parcels from ArcGIS REST │
│    geodata.hawaii.gov/.../ParcelsZoning      │
│    1000-parcel batches, polite delay 250ms   │
│    Checkpoint + resume on failure            │
└──────────────────────────────────────────────┘
              │
              ▼
┌──────────────────────────────────────────────┐
│ 2. Per-batch JSON → per-parcel .ts files     │
│    packages/parcels/src/{island}/{plat}/     │
│    {tmk}.ts                                  │
│    Each file ~47 lines, fully typed          │
└──────────────────────────────────────────────┘
              │
              ▼
┌──────────────────────────────────────────────┐
│ 3. Honolulu DPP building footprints          │
│    GeoJSON download, parse with proj4 to     │
│    EPSG:4326, extract per-building height    │
│    from elevationmax — elevationbase         │
└──────────────────────────────────────────────┘
              │
              ▼
┌──────────────────────────────────────────────┐
│ 4. Address-point index                       │
│    Honolulu open data CSV → searchable       │
│    in-memory index, mapped to TMK            │
└──────────────────────────────────────────────┘
              │
              ▼
┌──────────────────────────────────────────────┐
│ 5. MapLibre + WebGL rendering                │
│    Bbox-aware lazy load                      │
│    Fill polygon for parcels                  │
│    Extrude polygon for buildings             │
│    Time-of-day shading via SunCalc           │
└──────────────────────────────────────────────┘

Building heights — the hard part

Honolulu DPP's building-footprint dataset includes per-feature elevationbase and elevationmax values. Subtract one from the other and you get usable building height in meters above the foundation. Pass that to MapLibre's fill-extrusion-height property, and every building in downtown Honolulu, Waikiki, and the residential ridges renders at correct height.

Caveats:

Performance — what makes the browser handle 384k parcels

Three tricks:

  1. Bbox lazy load. The map only requests the batches that intersect the current viewport. Zoomed out to the whole state, the browser loads <5,000 parcels. Zoomed into Kahala, ~1,200. We never push more than a few hundred KB of JSON in any single tick.
  2. Server-side cache. The Node server reads each batch JSON from disk once, holds in-memory. Subsequent fetches serve from RAM. ~/server/hawaii-as-code/scripts/serve-api.ts handles all of this in a single ~1700-line file.
  3. MapLibre handles the rest. WebGL polygon fill + extrusion is one of the cheapest things a modern GPU can render. The bottleneck is JSON parsing, not GPU upload.

What it took

The first scrape ran 11 hours (rate-limited politely to not abuse the State GIS server). Building-footprint join took another 3 hours. Address-point indexing was an afternoon. The MapLibre rendering layer was 2 days of styling iteration. The TypeScript generator + per-parcel emission was the longest single chunk — roughly a week to get the schema, naming, file layout, and rollup indexes feeling right.

Total wall-clock from "this would be cool" to public-facing live map: ~10 days. Codebase open-sourced on GitHub at portofcams/hawaii-as-code.

What it's for

The 3D map is the visual surface for everything else IkenaAI does. Click a building, see its TMK + parcel info. Search an address, fly to the parcel. Run a Property Brief from the popup. The map is also the marketing front-door — it's the kind of thing you show people once and they never forget the URL.

Open the 3D map

Best on desktop with a real GPU. Pan, zoom, click any building, time-of-day shading, voice control.

Open the map →

What's next

We'll write up each as it ships. Bookmark the Field Notes if interested.

Working on a real Hawaii project?
Talk to Ikena directly. Real human follow-up within 24 hours.
Talk to Ikena →
Hawaii Property Notes — weekly
Wednesday-morning email — new posts, threads from the field, parcel of the week. No spam, unsubscribe any time.