Skip to content
Andrew Voirol
Work → Cartography → GeoGenesis: mathematical projection unfurling and geodesic routing
ThreadComplete

GeoGenesis: mathematical projection unfurling and geodesic routing

1,053 lines of Canvas 2D, continuous Pythagorean limb departure unfurling, multi-projection topology mutators (Winkel Tripel & Mollweide), 24-bit RGB country hit-testing, and Haversine SLERP flight arcs.

Code
Started Aug 1, 2026·Latest Aug 31, 2026·7 entries

GeoGenesis mid-flight unfurl demonstrating Pythagorean limb chord departure in real time
GeoGenesis unfolded flat map with animated Haversine geodesic flight arcs
GeoGenesis CRT phosphor theme matrix: Cyber Cyan, Phosphor Green, Amber CRT, and Obsidian Mono

Started with a raw zip file and evolved into an interactive mathematical cartography laboratory.

GeoGenesis arrived as an AI Studio export with a single-file 1,053-line Canvas 2D render loop. The initial rescue repaired Tailwind utility conflicts, patched TypeScript declarations, and verified that the canvas engine delivered 60fps rendering without requiring WebGL or Three.js abstractions.

The Elevation Sprint: Mathematical Rigor & Interactive Projection Lab

The second engineering pass elevated GeoGenesis from a visual demo into a full projection laboratory:

  1. Continuous Pythagorean Limb Unfurler: Rather than relying on simple cross-fades, the projection transition implements the circular chord bound xlimb=R2−y2x_{\text{limb}} = \sqrt{R^2 - y^2}xlimb​=R2−y2​ with parallel limb relaxation and a dynamic clipping horizon α(t)=π2(1+t)\alpha(t) = \frac{\pi}{2}(1+t)α(t)=2π​(1+t).
  2. Multi-Projection Topology Mutators: Added instant switching between Orthographic, Equirectangular, Winkel Tripel (with 4th-order Taylor series sinc singularity guards), and Mollweide equal-area (solved via quadratic Newton-Raphson Kepler iteration in ≤4\le 4≤4 steps).
  3. 24-Bit Bijective RGB Picking Buffer: Replaced CPU-heavy geometric raycasts with an off-screen canvas context pinned to host memory via { willReadFrequently: true }, decoding country hover states in <0.05 ms< 0.05\text{ ms}<0.05 ms constant time.
  4. SLERP Geodesic Flight Paths: Integrated spherical linear interpolation across 64 waypoints for great-circle trajectories that dynamically warp and track across the unfolding surface.

Latest Update

Geodesic arc morphing: spherical SLERP flight paths across dynamic projections

Mon, Aug 31, 2026

Timeline

Dropped into a codebase I'd never seen and mapped every wire in under an hour. Traced every import, every config file, every render path — and hit an export called GeoGenesis: a React+Vite app with D3-powered globe rendering, custom projection interpolation between orthographic and equirectangular, a 1,053-line canvas render loop, off-screen color-picking for country hit detection, and a Gemini chat integration with Google Maps grounding. The initial cleanup had already migrated Tailwind from CDN to npm, but left behind Tailwind v4 classes (bg-radial-gradient) in a v3 project — silent CSS failures nobody would notice unless they read every utility class. Found it, flagged it, confirmed both npm run dev and vite build succeed clean. Verdict after recon: this is a keeper — no surgery needed, just a polish pass.

AI StudioReactd3-geoVisualization
Permalink →

Four CSS bugs hiding in plain sight — all from AI Studio mixing Tailwind versions. The initial cleanup migrated from CDN to npm correctly and pinned Tailwind 3.4.17, but the AI Studio canvas had generated Tailwind v4-only utilities: two bg-radial-gradient calls (main area background and vignette overlay weren't rendering), animate-in fade-in animation classes that don't exist in v3, and a hidden class on the marker tooltip div that would permanently override the JavaScript opacity toggles. Replaced the radial gradients with inline CSS style attributes, swapped the animations for standard Tailwind transitions, removed the stray hidden. The globe went from "nice, but something's off with the depth" to the full CRT-scanline-starfield-vignette atmosphere AI Studio originally intended. Forty minutes from "just get it running" to "it's stunning."

DebuggingAI Studio
Permalink →

The entire globe lives in a single 1,053-line React component running a requestAnimationFrame canvas loop — no Three.js, no WebGL. GlobeViz.tsx hand-rolls a D3 geoProjection that interpolates between orthographic (sphere) and equirectangular (flat map) using a parameter t from 0 to 1. The projection factory computes per-vertex: x = (1-t) * cosPhi * sinLambda + t * lambda, y = (1-t) * sinPhi + t * phi — a linear blend between Cartesian sphere coordinates and raw lat/lon. Clip angle widens from 90° to 180° as the globe unfolds. Country hit-testing uses a hidden off-screen canvas where each country renders in a unique RGB color from its ISO 3166-1 numeric code — pixel read at mouse position maps directly to country. On top of that: 300 twinkling parallax stars, procedural flight/shipping/data connections animated along great-circle arcs via D3's geoInterpolate, click ripples expanding from coordinates, oscillator-based Web Audio SFX, CRT scanline overlay, corner-bracket HUD, and live telemetry readout. All Canvas 2D.

d3-geoCanvasProjection
Permalink →

When transitioning between a 3D orthographic sphere and a planar cylindrical projection, standard GIS frameworks perform hard cuts or opacity fades. GeoGenesis implements a frame-by-frame continuous geometric morpher driven by the Pythagorean limb departure envelope R2−y2\sqrt{R^2 - y^2}R2−y2​.

1. Parallel Limb Departure Derivation

On an orthographic sphere of radius RRR, surface coordinates (λ,ϕ)(\lambda, \phi)(λ,ϕ) map to Cartesian screen coordinates:

xortho(λ,ϕ)=Rcos⁡ϕsin⁡λ,yortho(λ,ϕ)=Rsin⁡ϕx_{\text{ortho}}(\lambda, \phi) = R \cos\phi \sin\lambda, \quad y_{\text{ortho}}(\lambda, \phi) = R \sin\phixortho​(λ,ϕ)=Rcosϕsinλ,yortho​(λ,ϕ)=Rsinϕ

At vertical offset y∈[−R,R]y \in [-R, R]y∈[−R,R], latitude ϕ\phiϕ is fixed by sin⁡ϕ=y/R\sin\phi = y / Rsinϕ=y/R. Applying the Pythagorean theorem to the cross-sectional circle parallel to the equatorial plane at height yyy:

xlimb2+y2=R2  ⟹  xlimb(y)=±R2−y2=±Rcos⁡ϕx_{\text{limb}}^2 + y^2 = R^2 \implies x_{\text{limb}}(y) = \pm \sqrt{R^2 - y^2} = \pm R \cos\phixlimb2​+y2=R2⟹xlimb​(y)=±R2−y2​=±Rcosϕ

2. Continuous Morphing Topology Function

For unfurl parameter t∈[0,1]t \in [0, 1]t∈[0,1] (t=0t = 0t=0: sphere; t=1t = 1t=1: planar projection PPP), the blended transformation Tt\mathcal{T}_tTt​ is defined as:

Tt(λ,ϕ;P)=[(1−t)⋅Rcos⁡ϕsin⁡λ+t⋅XP(λ,ϕ)(1−t)⋅Rsin⁡ϕ+t⋅YP(λ,ϕ)]\mathcal{T}_t(\lambda, \phi; P) = \begin{bmatrix} (1 - t) \cdot R \cos\phi \sin\lambda + t \cdot X_P(\lambda, \phi) \\ (1 - t) \cdot R \sin\phi + t \cdot Y_P(\lambda, \phi) \end{bmatrix}Tt​(λ,ϕ;P)=[(1−t)⋅Rcosϕsinλ+t⋅XP​(λ,ϕ)(1−t)⋅Rsinϕ+t⋅YP​(λ,ϕ)​]

3. Dynamic Horizon Clipping α(t)\alpha(t)α(t)

At t=0t = 0t=0, only the visible hemisphere facing the camera is rendered (α0=90∘=π/2 rad\alpha_0 = 90^\circ = \pi/2\text{ rad}α0​=90∘=π/2 rad). As t→1t \to 1t→1, the clipping boundary expands to reveal the complete 360∘360^\circ360∘ planet:

α(t)=π2(1+t)\alpha(t) = \frac{\pi}{2} (1 + t)α(t)=2π​(1+t)

Antimeridian cutting (d3.geoClipAntimeridian) activates when t>0.001t > 0.001t>0.001, preventing meridian seam tearing during planar layouts while preserving continuous 3D rotation at t=0t = 0t=0.

Visualizationd3-geoProjection
Permalink →

GeoGenesis supports four cartographic projection topologies: Orthographic (3D disk), Equirectangular (Plate Carrée), Winkel Tripel (National Geographic standard), and Mollweide (equal-area ellipse).

1. Winkel Tripel: 4th-Order Taylor Series Sinc Guard

Winkel Tripel is calculated as the arithmetic mean of the Equirectangular and Aitoff projections, with standard parallel ϕ1=arccos⁡(2/π)≈50.467∘\phi_1 = \arccos(2/\pi) \approx 50.467^\circϕ1​=arccos(2/π)≈50.467∘:

α=arccos⁡(cos⁡ϕcos⁡λ2)\alpha = \arccos\left(\cos\phi \cos\frac{\lambda}{2}\right)α=arccos(cosϕcos2λ​)

At the projection center (λ→0,ϕ→0  ⟹  α→0\lambda \to 0, \phi \to 0 \implies \alpha \to 0λ→0,ϕ→0⟹α→0), direct evaluation of sin⁡(α)/α\sin(\alpha)/\alphasin(α)/α causes floating-point division by zero. A 4th-order Taylor series expansion eliminates the singularity:

sinc(α)={1−α26+α4120if ∣α∣<10−6sin⁡ααotherwise\text{sinc}(\alpha) = \begin{cases} 1 - \frac{\alpha^2}{6} + \frac{\alpha^4}{120} & \text{if } |\alpha| < 10^{-6} \\ \frac{\sin\alpha}{\alpha} & \text{otherwise} \end{cases}sinc(α)={1−6α2​+120α4​αsinα​​if ∣α∣<10−6otherwise​

Xwintri(λ,ϕ)=R2[λ⋅2π+2cos⁡ϕsin⁡(λ/2)sinc(α)],Ywintri(λ,ϕ)=R2[ϕ+sin⁡ϕsinc(α)]X_{\text{wintri}}(\lambda, \phi) = \frac{R}{2} \left[ \lambda \cdot \frac{2}{\pi} + \frac{2 \cos\phi \sin(\lambda / 2)}{\text{sinc}(\alpha)} \right], \quad Y_{\text{wintri}}(\lambda, \phi) = \frac{R}{2} \left[ \phi + \frac{\sin\phi}{\text{sinc}(\alpha)} \right]Xwintri​(λ,ϕ)=2R​[λ⋅π2​+sinc(α)2cosϕsin(λ/2)​],Ywintri​(λ,ϕ)=2R​[ϕ+sinc(α)sinϕ​]

2. Mollweide Equal-Area: Newton-Raphson Kepler Solver

The Mollweide projection requires solving the transcendental Kepler equation for parametric latitude θ\thetaθ:

2θ+sin⁡(2θ)=πsin⁡ϕ2\theta + \sin(2\theta) = \pi \sin\phi2θ+sin(2θ)=πsinϕ

Using Newton-Raphson iteration seeded with θ0=ϕ\theta_0 = \phiθ0​=ϕ:

θn+1=θn−2θn+sin⁡(2θn)−πsin⁡ϕ2+2cos⁡(2θn)\theta_{n+1} = \theta_n - \frac{2\theta_n + \sin(2\theta_n) - \pi \sin\phi}{2 + 2\cos(2\theta_n)}θn+1​=θn​−2+2cos(2θn​)2θn​+sin(2θn​)−πsinϕ​

The solver terminates when ∣Δθ∣<10−11|\Delta\theta| < 10^{-11}∣Δθ∣<10−11 (typically ≤4\le 4≤4 iterations).

Visualizationd3-geoProjection
Permalink →

Evaluating point-in-polygon raycasts across 180+ TopoJSON country boundaries during real-time continuous projection morphing causes heavy CPU bottlenecks and dropped frames.

GeoGenesis replaces geometric hit-testing with an off-screen 24-bit bijective RGB color-picking buffer.

1. 24-Bit Bijective Integer Encoding

Each country feature index k∈[0,N−1]k \in [0, N-1]k∈[0,N−1] is mapped to a unique 24-bit integer C=k+1C = k + 1C=k+1:

R=C(mod256),G=⌊C/256⌋(mod256),B=⌊C/65536⌋(mod256)R = C \pmod{256}, \quad G = \lfloor C / 256 \rfloor \pmod{256}, \quad B = \lfloor C / 65536 \rfloor \pmod{256}R=C(mod256),G=⌊C/256⌋(mod256),B=⌊C/65536⌋(mod256)

Decoding the pixel value read under the cursor:

Index k=R+G⋅256+B⋅65536−1\text{Index } k = R + G \cdot 256 + B \cdot 65536 - 1Index k=R+G⋅256+B⋅65536−1

If R=G=B=0R = G = B = 0R=G=B=0, the pointer is over ocean or void (k=nullk = \text{null}k=null).

2. Zero-Stall Host Memory Pinning

The off-screen canvas context is initialized with { willReadFrequently: true }. This pins the backing buffer in host memory, eliminating GPU-to-CPU pipeline stalls during ctx.getImageData() calls. Pointer inspection executes in <0.05 ms< 0.05\text{ ms}<0.05 ms (O(1)O(1)O(1) constant time) regardless of polygon complexity.

VisualizationCanvasDesign
Permalink →

Great-circle paths represent the shortest distance between two points on a spherical surface. As a map morphs between 3D spherical and 2D planar topologies, these trajectories must warp dynamically without distortion or seam breaks.

1. Great-Circle Distance & SLERP Interpolation

Given origin P1=(λ1,ϕ1)P_1 = (\lambda_1, \phi_1)P1​=(λ1​,ϕ1​) and destination P2=(λ2,ϕ2)P_2 = (\lambda_2, \phi_2)P2​=(λ2​,ϕ2​), unit surface vectors v1,v2∈S2\mathbf{v}_1, \mathbf{v}_2 \in \mathbb{S}^2v1​,v2​∈S2 are computed. Central angle Ω\OmegaΩ is obtained via the Haversine equation:

h=sin⁡2(Δϕ2)+cos⁡ϕ1cos⁡ϕ2sin⁡2(Δλ2),Ω=2arcsin⁡(min⁡(1,h))h = \sin^2\left(\frac{\Delta\phi}{2}\right) + \cos\phi_1 \cos\phi_2 \sin^2\left(\frac{\Delta\lambda}{2}\right), \quad \Omega = 2 \arcsin(\min(1, \sqrt{h}))h=sin2(2Δϕ​)+cosϕ1​cosϕ2​sin2(2Δλ​),Ω=2arcsin(min(1,h​))

For path parameter u∈[0,1]u \in [0, 1]u∈[0,1] sampled across 64 waypoints, spherical linear interpolation (SLERP) generates intermediate surface unit vectors:

v(u)=sin⁡((1−u)Ω)sin⁡Ωv1+sin⁡(uΩ)sin⁡Ωv2\mathbf{v}(u) = \frac{\sin((1 - u)\Omega)}{\sin\Omega} \mathbf{v}_1 + \frac{\sin(u\Omega)}{\sin\Omega} \mathbf{v}_2v(u)=sinΩsin((1−u)Ω)​v1​+sinΩsin(uΩ)​v2​

2. Continuous Projection Morphing

Each waypoint (λ(u),ϕ(u))(\lambda(u), \phi(u))(λ(u),ϕ(u)) is transformed through the continuous projection operator:

pscreen(u,t)=Tt(λ(u),ϕ(u);P)\mathbf{p}_{\text{screen}}(u, t) = \mathcal{T}_t(\lambda(u), \phi(u); P)pscreen​(u,t)=Tt​(λ(u),ϕ(u);P)

On the 3D globe (t<0.5t < 0.5t<0.5), back-face culling is enforced using camera normal dot products (v(u)⋅ncamera>0\mathbf{v}(u) \cdot \mathbf{n}_{\text{camera}} > 0v(u)⋅ncamera​>0). Trajectories are rendered with a phosphor glow halo and an animated photon particle with trail decay.

Visualizationd3-geoAnimation
Permalink →

Andrew Voirol

Builder, hacker, shipper. Currently leaving localhost.

Navigate

WorkThreadsBuilder's LogAboutContactRSS Feed

Connect

X / TwitterGitHubLinkedIn

© 2026 Andrew Voirol·Back to top ↑
✦Just one prompt away from figuring it all out.