<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Threejs on kmcd.dev</title><link>https://kmcd.dev/tags/threejs/</link><description>Recent content in Threejs on kmcd.dev</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>All Rights Reserved</copyright><lastBuildDate>Sun, 18 Oct 2026 10:00:00 +0000</lastBuildDate><atom:link href="https://kmcd.dev/tags/threejs/index.xml" rel="self" type="application/rss+xml"/><item><title>Visualizing the Internet (2026) - Part 2</title><link>https://kmcd.dev/posts/internet-map-2026-part-2/</link><pubDate>Sun, 18 Oct 2026 10:00:00 +0000</pubDate><guid>https://kmcd.dev/posts/internet-map-2026-part-2/</guid><description> 
                &lt;p> &lt;img hspace="5" src="https://kmcd.dev/posts/internet-map-2026-part-2/cover_hu_4b0c81b8d24f49b1.webp" /> &lt;/p>
                
                Updating map.kmcd.dev with an interactive 3D globe, more BGP cities, historical submarine cables back to 1858, and live internet outage alerts.
                </description><content:encoded><![CDATA[<p>In my <a href="https://kmcd.dev/posts/internet-map-2026/">February post</a> about the <a href="https://map.kmcd.dev" rel="external">Internet Infrastructure Map</a>, I ended with &ldquo;See You Next Year.&rdquo; I usually only touch the map once a year when I pull new data and write up an annual update. This year I kept tinkering with it anyway, and enough has changed that it didn&rsquo;t feel right waiting until next February. You can check out the current version at <strong><a href="https://map.kmcd.dev" rel="external">map.kmcd.dev</a></strong>.</p>
<div class="diagram-wrapper">
    <span class="diagram"
        style="">
<figure><a href="https://kmcd.dev/posts/internet-map-2026-part-2/globe-overview.png" class="spotlight" data-download="true" aria-label="The new 3D globe view on map.kmcd.dev">
    
    
    
    
        
            
            
                
            
            
        
    

    
    
    
        
        
    
    

    
    
        
    

    <img src="https://kmcd.dev/posts/internet-map-2026-part-2/globe-overview_hu_e497e2471caa5c24.png"
         class="img-fade-in"
         onload="this.classList.add('is-loaded')"
         alt="The new 3D globe view on map.kmcd.dev" width="1200" height="713" style="aspect-ratio: 1200 / 713;" loading="lazy"/>
    </a><figcaption>
            <p>The 3D globe view @ <strong><a href="https://map.kmcd.dev" rel="external">map.kmcd.dev</a></strong></p>
        </figcaption>
</figure>


    </span>

    
</div>

<h2 id="3d-globe">3D Globe</h2>
<p>Up until now, the map used <a href="https://leafletjs.com/" rel="external">Leaflet</a>. The tileset I was using with Leaflet dropped its free tier and started requiring a paid API key. I found an alternative for a while, but I didn&rsquo;t like how things felt. This update is the end result of that saga: I replaced Leaflet with <strong>Three.js</strong> and ditched standard map tiles altogether. Instead, I use an SVG for the country lines and rasterize it (with a cache) to an offscreen <code>&lt;canvas&gt;</code> texture for the visible viewport whenever zoom settles, so borders stay sharp at any zoom level. The <strong>3D Globe</strong> is now the default, though you can still switch back to the 2D view (which swaps to an orthographic Web Mercator Three.js scene while keeping your camera position synced).</p>
<div class="diagram-wrapper">
    <span class="diagram"
        style="">











    
        
    



    
        
    




    




    


<figure>
    <div style="display: flex; gap: 10px;">
        <div style="flex: 1;">
            <p><strong>Before:</strong></p>
            <img src="https://kmcd.dev/posts/internet-map-2026-part-2/view-globe_hu_24dcfe5aad4e1fcf.png" alt="Before" style="max-width: 100%; height: auto;">
        </div>
        <div style="flex: 1;">
            <p><strong>After:</strong></p>
            <img src="https://kmcd.dev/posts/internet-map-2026-part-2/view-2d_hu_5d54c01b9a66ba49.png" alt="After" style="max-width: 100%; height: auto;">
        </div>
    </div>
    
    <figcaption>The 3D Globe and the 2D map.</figcaption>
    
</figure>


    </span>

    
</div>

<p>For the cables on the 3D globe, I added two ways to view them. In <strong>Arches</strong> mode, cables arc above the globe between landing stations with animated pulses. In <strong>Surface</strong> mode, the cables stay flat along their estimated undersea routes.</p>
<div class="diagram-wrapper">
    <span class="diagram"
        style="">











    
        
    



    
        
    




    




    


<figure>
    <div style="display: flex; gap: 10px;">
        <div style="flex: 1;">
            <p><strong>Before:</strong></p>
            <img src="https://kmcd.dev/posts/internet-map-2026-part-2/cables-surface_hu_ca447f95aa0ae07e.png" alt="Before" style="max-width: 100%; height: auto;">
        </div>
        <div style="flex: 1;">
            <p><strong>After:</strong></p>
            <img src="https://kmcd.dev/posts/internet-map-2026-part-2/cables-arches_hu_92c0d1d1c288326b.png" alt="After" style="max-width: 100%; height: auto;">
        </div>
    </div>
    
    <figcaption>Surface cables vs. 3D arches.</figcaption>
    
</figure>


    </span>

    
</div>

<h2 id="more-bgp-data">More BGP Data</h2>
<p>In <a href="https://kmcd.dev/posts/internet-map-2026/">Part 1</a>, I only mapped IPv4 BGP routes and filtered out smaller cities to keep the map from bogging down. This time I added IPv6 routes (measured by announced subnet count rather than raw address count so a single <code>/64</code> doesn&rsquo;t dwarf the entire IPv4 internet), kept all of the smaller cities on the map, and pulled historical GeoIP snapshots for each year back to 2010 instead of relying on a single modern database. Zooming in also adds text labels for the largest cities in view.</p>
<div class="diagram-wrapper">
    <span class="diagram"
        style="">
<figure><a href="https://kmcd.dev/posts/internet-map-2026-part-2/hub-closeup.png" class="spotlight" data-download="true" aria-label="Zoomed-in view of Western Europe showing city labels and BGP cities">
    
    
    
    
        
            
            
                
            
            
        
    

    
    
    
        
        
    
    

    
    
        
    

    <img src="https://kmcd.dev/posts/internet-map-2026-part-2/hub-closeup_hu_44d3b2dd2442cfbc.png"
         class="img-fade-in"
         onload="this.classList.add('is-loaded')"
         alt="Zoomed-in view of Western Europe showing city labels and BGP cities" width="1200" height="713" style="aspect-ratio: 1200 / 713;" loading="lazy"/>
    </a><figcaption>
            <p>Western Europe with individual BGP cities and city labels.</p>
        </figcaption>
</figure>


    </span>

    
</div>

<p>On the map, blue dots are cities with public IXP peering and purple dots are cities that only announce BGP IP space. Once I put all of the smaller cities on the globe, I kept noticing big purple dots sitting right on top of major fiber lines with millions of IPs and no local IXP at all. I&rsquo;m working on a follow-up post about why that happens and what it does to your traffic if you live in one of those cities.</p>
<p>Rather than manually running the data scripts once a year, the map data now updates automatically on the first of every month from the latest BGP routing tables and PeeringDB snapshots.</p>
<h2 id="layers-and-filtering">Layers and Filtering</h2>
<p>You can toggle individual layers (text labels, outage alerts, cable display mode, peering capacity, IPv4 addresses, and IPv6 subnets) from the layers menu in the top toolbar:</p>
<div class="diagram-wrapper">
    <span class="diagram"
        style=" width:300px;">
<figure><a href="https://kmcd.dev/posts/internet-map-2026-part-2/layers-menu.png" class="spotlight" data-download="true" aria-label="The layers menu in the top toolbar">
    
    
    
    
        
            
            
                
                
            
            
        
    

    
    
    
        
        
    
    
        
        
            
        
        
    

    
    
        
    

    <img src="https://kmcd.dev/posts/internet-map-2026-part-2/layers-menu_hu_b47b8c46b20b82c.png"
         class="img-fade-in"
         onload="this.classList.add('is-loaded')"
         alt="The layers menu in the top toolbar" width="600" height="636" style="aspect-ratio: 600 / 636;" loading="lazy"/>
    </a><figcaption>
            <p>The layers menu for toggling text, outage alerts, cable display mode, peering, IPv4 space, and IPv6 subnets.</p>
        </figcaption>
</figure>


    </span>

    
</div>

<p>The search bar in the toolbar also filters both the 3D globe and 2D map across cables, cities, and countries at once. For example, filtering for <code>France</code> isolates every submarine cable landing in France alongside its peering and BGP cities:</p>
<div class="diagram-wrapper">
    <span class="diagram"
        style="">
<figure><a href="https://kmcd.dev/posts/internet-map-2026-part-2/search-france.png" class="spotlight" data-download="true" aria-label="Filtering the map for France">
    
    
    
    
        
            
            
                
            
            
        
    

    
    
    
        
        
    
    

    
    
        
    

    <img src="https://kmcd.dev/posts/internet-map-2026-part-2/search-france_hu_595c9613b0a9f9fc.png"
         class="img-fade-in"
         onload="this.classList.add('is-loaded')"
         alt="Filtering the map for France" width="1200" height="713" style="aspect-ratio: 1200 / 713;" loading="lazy"/>
    </a><figcaption>
            <p>Searching for &lsquo;France&rsquo; isolates French cities and every submarine cable landing in the country.</p>
        </figcaption>
</figure>


    </span>

    
</div>

<h2 id="performance">Performance</h2>
<p>Putting all of those cities and cables onto a 3D globe at once initially made the page very slow, both on initial load and when zooming in and out.</p>
<p>To keep initial page loads fast and the map running at 60 FPS, the initial view loads a pre-clustered global overview while a Web Worker streams in regional city tiles on demand as you zoom in and handles the clustering off the main thread. I also shrank the initial download by delta-encoding the country boundary GeoJSON and trimming coordinate precision on the cable routes. Hovering over a cable used to rebuild its Three.js geometry on every mouse move. Now all cables are merged into a single mesh where a texture update highlights the selected route, and raycasting is disabled on the background country polygons.</p>
<h2 id="historical-data">Historical Data</h2>
<p>If you dragged the timeline slider back to the 1990s or early 2000s on the old map, a lot of old cables were either missing or had the wrong activation and retirement years. I went through historical cable records to add the missing systems and fix retirement dates. You can also download the full list of cables (from 1858 to 2026) as a CSV at <strong><a href="https://data.map.kmcd.dev/cables.csv" rel="external">cables.csv</a></strong>. If you notice any errors in the data, please <a href="https://kmcd.dev/me/">reach out</a>.</p>
<div class="diagram-wrapper">
    <span class="diagram"
        style="">
<figure><a href="https://kmcd.dev/posts/internet-map-2026-part-2/historical-timeline.png" class="spotlight" data-download="true" aria-label="Decommissioned historical submarine cables view">
    
    
    
    
        
            
            
                
            
            
        
    

    
    
    
        
        
    
    

    
    
        
    

    <img src="https://kmcd.dev/posts/internet-map-2026-part-2/historical-timeline_hu_bea578b57feed0f5.png"
         class="img-fade-in"
         onload="this.classList.add('is-loaded')"
         alt="Decommissioned historical submarine cables view" width="1200" height="713" style="aspect-ratio: 1200 / 713;" loading="lazy"/>
    </a><figcaption>
            <p>Filtering for <a href="https://map.kmcd.dev/?q=decomm" rel="external">decommissioned cables (<code>q=decomm</code>)</a> across the historical dataset.</p>
        </figcaption>
</figure>


    </span>

    
</div>

<p>There is also a new <strong>Statistics</strong> panel that updates as you move the timeline slider or type in a search filter, showing how many cables are active and how much bandwidth each region has in that year:</p>
<div class="diagram-wrapper">
    <span class="diagram"
        style="">
<figure><a href="https://kmcd.dev/posts/internet-map-2026-part-2/statistics-panel.png" class="spotlight" data-download="true" aria-label="The Statistics panel on map.kmcd.dev">
    
    
    
    
        
            
            
                
            
            
        
    

    
    
    
        
        
    
    

    
    
        
    

    <img src="https://kmcd.dev/posts/internet-map-2026-part-2/statistics-panel_hu_7b1c7da023657b19.png"
         class="img-fade-in"
         onload="this.classList.add('is-loaded')"
         alt="The Statistics panel on map.kmcd.dev" width="1200" height="713" style="aspect-ratio: 1200 / 713;" loading="lazy"/>
    </a><figcaption>
            <p>The Statistics panel for the selected year.</p>
        </figcaption>
</figure>


    </span>

    
</div>

<h2 id="outage-alerts">Outage Alerts</h2>
<p>I also wanted <code>map.kmcd.dev</code> to show active internet disruptions alongside the physical and routing layers. The map now pulls outage and anomaly alerts from <strong><a href="https://radar.cloudflare.com/outage-center" rel="external">Cloudflare Radar</a></strong> and <strong><a href="https://ioda.inetintel.cc.gatech.edu/" rel="external">IODA</a></strong> (Internet Outage Detection and Analysis) every 15 minutes and overlays them directly onto the globe.</p>
<div class="diagram-wrapper">
    <span class="diagram"
        style="">
<figure><a href="https://kmcd.dev/posts/internet-map-2026-part-2/cloudflare-alerts.png" class="spotlight" data-download="true" aria-label="Active outage alert on the map">
    
    
    
    
        
            
            
                
            
            
        
    

    
    
    
        
        
    
    

    
    
        
    

    <img src="https://kmcd.dev/posts/internet-map-2026-part-2/cloudflare-alerts_hu_d3b5399580831bf.png"
         class="img-fade-in"
         onload="this.classList.add('is-loaded')"
         alt="Active outage alert on the map" width="1200" height="713" style="aspect-ratio: 1200 / 713;" loading="lazy"/>
    </a><figcaption>
            <p>Active outage alerts on the map, with links to Cloudflare Radar.</p>
        </figcaption>
</figure>


    </span>

    
</div>

<p>Countries with an active outage highlight in red on the globe, and clicking the alert badge opens the incident details with a link out to the upstream outage report. When I first added this, I forgot to hide the alerts when scrubbing the timeline slider, so for a day or two it looked like Cloudflare was reporting live outages in 1995.</p>
<h2 id="end">End</h2>
<p>We&rsquo;ll have to see what direction this takes next year. I&rsquo;m really happy with how the project has evolved, starting as a simple rendering of submarine cables and growing into a map that glues together routing tables, peering databases, historical archives, and live outage feeds into a single view.</p>
<p>You can explore the updated map here: <strong><a href="https://map.kmcd.dev" rel="external">map.kmcd.dev</a></strong></p>
]]></content:encoded></item></channel></rss>