<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harsh Jhunjhunuwala</title>
    <description>The latest articles on DEV Community by Harsh Jhunjhunuwala (@harsh_jhunjhunuwala).</description>
    <link>https://dev.to/harsh_jhunjhunuwala</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4125206%2F29794001-5529-42ba-adb6-e732fee350ce.png</url>
      <title>DEV Community: Harsh Jhunjhunuwala</title>
      <link>https://dev.to/harsh_jhunjhunuwala</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harsh_jhunjhunuwala"/>
    <language>en</language>
    <item>
      <title>I built an interactive globe without WebGL or map tiles</title>
      <dc:creator>Harsh Jhunjhunuwala</dc:creator>
      <pubDate>Tue, 15 Sep 2026 03:30:00 +0000</pubDate>
      <link>https://dev.to/harsh_jhunjhunuwala/i-built-an-interactive-globe-without-webgl-or-map-tiles-2jkn</link>
      <guid>https://dev.to/harsh_jhunjhunuwala/i-built-an-interactive-globe-without-webgl-or-map-tiles-2jkn</guid>
      <description>&lt;p&gt;The requirement sounded small: put an interactive globe on a web page.&lt;/p&gt;

&lt;p&gt;I wanted people to drag it, zoom it, hover over countries, place markers, and show routes between locations. I also wanted it to fit naturally inside dashboards, launch pages, status boards, and visual reports.&lt;/p&gt;

&lt;p&gt;When I explored the available options, I kept finding tools built for a bigger job. Some focused on advanced 3D effects. Others were complete mapping platforms. Both are useful, but I did not want every project to set up a map provider, load map tiles, or create an entire 3D scene just to show a focused globe visual.&lt;/p&gt;

&lt;p&gt;So I wrote down a few rules for my own library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it should use the browser's regular 2D canvas;&lt;/li&gt;
&lt;li&gt;it should not need a map API key;&lt;/li&gt;
&lt;li&gt;it should not make required network requests while running;&lt;/li&gt;
&lt;li&gt;it should have no runtime dependencies; and&lt;/li&gt;
&lt;li&gt;the same data should work on a globe and on a flat world map.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That project became &lt;a href="https://canvasglobe.swiftools.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=public_launch" rel="noopener noreferrer"&gt;CanvasGlobe&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://canvasglobe.swiftools.com/playground?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=public_launch" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feux0j93bafb23ae935xi.gif" alt="Animated CanvasGlobe demo cycling through globe themes, markers, and routes" width="760" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The public API ended up being fairly small. The surprising part was how many visual problems were hiding behind that simple circle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawing a circle was the easy part
&lt;/h2&gt;

&lt;p&gt;The globe uses an orthographic projection. In plain language, it shows one half of Earth as if you were looking at it from very far away. This creates the familiar round globe shape without needing a 3D engine.&lt;/p&gt;

&lt;p&gt;For each location, the library calculates three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;its horizontal position;&lt;/li&gt;
&lt;li&gt;its vertical position; and&lt;/li&gt;
&lt;li&gt;whether it is on the front or back of the globe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last answer is what makes the flat canvas feel three-dimensional. A marker on the back should disappear. A route should travel behind the globe instead of showing through it. Countries near the edge should gradually leave the visible side.&lt;/p&gt;

&lt;p&gt;The browser is still drawing pixels on a 2D canvas. The sense of depth comes from hiding the right things, changing their size, adding shading, and moving everything consistently when the globe rotates.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first version fell apart at the edge
&lt;/h2&gt;

&lt;p&gt;At first, hiding points on the back sounded sufficient. It worked for markers, but countries are not single points. A country near the edge of the globe can be partly visible and partly hidden.&lt;/p&gt;

&lt;p&gt;If I simply removed the hidden part, the country shape was left open. Filled areas could flicker or draw strange lines across the globe while it moved.&lt;/p&gt;

&lt;p&gt;The solution was to find the exact places where a country's outline crosses the visible edge. The library draws the visible part, follows the circular edge of the globe across the hidden gap, and then continues when the country comes back into view.&lt;/p&gt;

&lt;p&gt;This small detail made a large visual difference. Before it, the result looked like a flat map placed inside a round mask. After it, countries appeared to move naturally around a sphere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routes could not just be straight lines
&lt;/h2&gt;

&lt;p&gt;The next feature I wanted was a route between two cities.&lt;/p&gt;

&lt;p&gt;Drawing a straight line between their longitude and latitude values works in a few cases, but it is not how the shortest route across a globe behaves. It also produces awkward results when a route crosses from one side of the world map to the other.&lt;/p&gt;

&lt;p&gt;Instead, CanvasGlobe calculates points along the surface of a sphere. This is commonly called a great-circle route. It is why long-distance flight paths often look curved on a flat map.&lt;/p&gt;

&lt;p&gt;The same route data can then be shown in two ways. On the globe, the hidden section passes behind the Earth. On a flat map, the path follows the selected map view.&lt;/p&gt;

&lt;p&gt;I liked this part of the design because the feature is not tied to one visual style. A user can switch between the globe and map without rebuilding the route data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The flat map had its own edge problem
&lt;/h2&gt;

&lt;p&gt;The globe naturally hides half of the world. A flat map has to decide where the world begins and ends.&lt;/p&gt;

&lt;p&gt;That boundary is usually placed near 180 degrees longitude, on the opposite side of the world from the main map center. It is known as the antimeridian.&lt;/p&gt;

&lt;p&gt;A country outline may contain one point at longitude &lt;code&gt;179&lt;/code&gt; and the next at &lt;code&gt;-179&lt;/code&gt;. Those points are actually close together, but a simple drawing command sees them on opposite sides of the canvas and draws a line across the entire map.&lt;/p&gt;

&lt;p&gt;CanvasGlobe detects that jump and starts a new section of the outline. When the map is zoomed and moved, it also shifts the world boundary away from the current view when possible.&lt;/p&gt;

&lt;p&gt;The globe and the flat map now share the same geographic data, but they handle their edges differently. Trying to force one drawing method onto both made the code look simpler and the map look worse, so I kept the two paths separate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hovering meant working backwards
&lt;/h2&gt;

&lt;p&gt;Drawing answers one question: where should a country appear on the canvas?&lt;/p&gt;

&lt;p&gt;Hovering asks the reverse: which country is under this pixel?&lt;/p&gt;

&lt;p&gt;The library first converts the pointer position back into a geographic location. A pointer outside the round globe can be rejected immediately. It then ignores countries whose broad boundaries are nowhere near that location and checks the remaining shapes more carefully.&lt;/p&gt;

&lt;p&gt;Markers use a simpler check. Their screen positions and clickable sizes are remembered during drawing, so the library only needs to measure the distance from the pointer.&lt;/p&gt;

&lt;p&gt;Keeping these two checks separate made everyday marker interaction fast without sacrificing country hover and click behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  An idle globe should be quiet
&lt;/h2&gt;

&lt;p&gt;Canvas does not remember objects like regular HTML does. When something changes, the scene must be drawn again.&lt;/p&gt;

&lt;p&gt;The easiest approach is to repaint on every screen refresh. That also wastes work when the globe is sitting still.&lt;/p&gt;

&lt;p&gt;CanvasGlobe keeps track of whether something actually changed and whether anything is still moving. It continues drawing during a drag, a smooth move to another location, automatic rotation, animated routes, or live effects. When the scene is idle, it avoids repainting the same frame.&lt;/p&gt;

&lt;p&gt;The drawing rate can also be limited. A decorative dashboard globe may not need to run at the highest rate a display supports.&lt;/p&gt;

&lt;p&gt;For the dotted-land theme, the library does another piece of work only once. It creates a small hidden picture of the land and uses that picture to decide which dots belong on countries. This is much cheaper than repeatedly checking every dot against every country outline.&lt;/p&gt;

&lt;p&gt;None of these changes is dramatic alone. Together, they help the library stay reasonable on pages where the globe is one component among many.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mouse support was not enough
&lt;/h2&gt;

&lt;p&gt;It was easy to make the globe pleasant with a mouse and still leave out people using a keyboard or reduced-motion settings.&lt;/p&gt;

&lt;p&gt;When interaction is enabled, the canvas can receive keyboard focus. Arrow keys rotate the view, plus and minus zoom, and &lt;code&gt;0&lt;/code&gt; resets it. Page Up and Page Down move between markers, while Enter or Space activates the selected marker.&lt;/p&gt;

&lt;p&gt;The library also listens to the browser's reduced-motion preference. If a user has asked for less motion, automatic rotation and non-essential animation are suppressed while direct controls continue to work.&lt;/p&gt;

&lt;p&gt;There is still an important limit here. Useful data should not exist only as pixels. A dashboard should provide a nearby table, summary, or another readable HTML view when people need the actual values.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same canvas could create the marketing assets
&lt;/h2&gt;

&lt;p&gt;I did not want one renderer for the live product and another for screenshots and social graphics.&lt;/p&gt;

&lt;p&gt;CanvasGlobe can draw the current scene onto a temporary canvas at a different size. That makes it possible to export square images, story images, Open Graph graphics, LinkedIn images, or transparent PNG files without resizing the globe people are currently using.&lt;/p&gt;

&lt;p&gt;For short video clips, it uses the browser's built-in canvas recording support. The frames are recorded and combined inside the tab, then returned as a downloadable file. Nothing has to be uploaded to a CanvasGlobe server.&lt;/p&gt;

&lt;p&gt;Video format support still differs between browsers, so image export remains the dependable fallback.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I chose not to build
&lt;/h2&gt;

&lt;p&gt;Using Canvas 2D solved the problem I had, but it also gave the project a clear boundary.&lt;/p&gt;

&lt;p&gt;CanvasGlobe is not the right choice for terrain, elevation, buildings, custom 3D models, street maps, advanced lighting, or thousands of separate objects in 3D space.&lt;/p&gt;

&lt;p&gt;For those jobs, I would look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/shuding/cobe" rel="noopener noreferrer"&gt;Cobe&lt;/a&gt; for a polished visual globe;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/vasturiano/globe.gl" rel="noopener noreferrer"&gt;globe.gl&lt;/a&gt; for richer 3D globe layers;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/maplibre/maplibre-gl-js" rel="noopener noreferrer"&gt;MapLibre GL JS&lt;/a&gt; for interactive maps built from map tiles; or&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/CesiumGS/cesium" rel="noopener noreferrer"&gt;CesiumJS&lt;/a&gt; for a complete 3D geographic platform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was not trying to replace those tools. I wanted to cover the space between a static globe illustration and a full mapping engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;canvas-globe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a canvas to the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"globe"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"width: min(100%, 560px); aspect-ratio: 1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a globe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createGlobe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;canvas-globe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;globe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createGlobe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#globe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;atlas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;markers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;23.03&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;72.58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ahmedabad&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;51.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;London&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;arcs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;72.58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;23.03&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;51.50&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;tooltip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;globe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flyTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;zoom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can explore the working project here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://canvasglobe.swiftools.com/playground?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=public_launch" rel="noopener noreferrer"&gt;Live playground&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://canvasglobe.swiftools.com/examples?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=public_launch" rel="noopener noreferrer"&gt;Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://6aa86f4b12c38527328d5256-thckvnyyjl.chromatic.com/" rel="noopener noreferrer"&gt;Interactive Storybook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Shree-hari/canvas-globe" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/canvas-globe" rel="noopener noreferrer"&gt;npm package&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CanvasGlobe is available under GPL-3.0-only for projects that comply with GPLv3. If you are distributing it in a proprietary product, you must purchase a commercial license. &lt;a href="https://canvasglobe.swiftools.com/pricing?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=public_launch" rel="noopener noreferrer"&gt;See the commercial plans and pricing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The library is still early. If you try it, I would genuinely like to know where the API feels awkward, how it behaves on lower-end mobile devices, and which real-world globe use cases are still missing.&lt;/p&gt;

&lt;p&gt;Disclosure: I am the author and licensor of CanvasGlobe.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
