earth-clock is a fork of earth that transforms the classic Earth weather visualization into a world clock with real-time day/night terminator overlay, inspired by World Clock.
This project extends the original earth visualization with:
- Real-time day/night terminator overlay - Shows which parts of the Earth are currently in daylight or darkness
- Current weather data integration - Automatically fetches and displays current GFS weather data
- Time display - Shows current time with UTC/Local toggle
- Native JavaScript weather service - No Java dependency required for weather data processing
You can view the live version at earth-clock.onemonkey.org.
The original "earth" project visualizes global weather conditions and is available at http://earth.nullschool.net. The original project is based on the earlier Tokyo Wind Map project.
After installing node.js and npm, clone "earth" and install dependencies:
git clone https://github.com/infantlab/earth-clock
cd earth-clock
npm install
Next, launch the development web server:
Using npm: npm start
Or using node directly: node dev-server.js 8080
Or using bun (if installed): bun dev-server.js 8080
Finally, point your browser to:
http://localhost:8080
The server acts as a stand-in for static S3 bucket hosting and so contains almost no server-side logic. It
serves all files located in the earth/public directory. See public/index.html and public/libs/earth/*.js
for the main entry points. Data files are located in the public/data directory, and there is one sample
weather layer located at data/weather/current.
*For Ubuntu, Mint, and elementary OS, use nodejs instead of node instead due to a naming conflict.
Map data is provided by Natural Earth but must be converted to TopoJSON format. We make use of a couple different map scales: a simplified, larger scale for animation and a more detailed, smaller scale for static display. After installing GDAL and TopoJSON (see here), the following commands build these files:
curl "http://www.nacis.org/naturalearth/50m/physical/ne_50m_coastline.zip" -o ne_50m_coastline.zip
curl "http://www.nacis.org/naturalearth/50m/physical/ne_50m_lakes.zip" -o ne_50m_lakes.zip
curl "http://www.nacis.org/naturalearth/110m/physical/ne_110m_coastline.zip" -o ne_110m_coastline.zip
curl "http://www.nacis.org/naturalearth/110m/physical/ne_110m_lakes.zip" -o ne_110m_lakes.zip
unzip -o ne_\*.zip
ogr2ogr -f GeoJSON coastline_50m.json ne_50m_coastline.shp
ogr2ogr -f GeoJSON coastline_110m.json ne_110m_coastline.shp
ogr2ogr -f GeoJSON -where "scalerank < 4" lakes_50m.json ne_50m_lakes.shp
ogr2ogr -f GeoJSON -where "scalerank < 2 AND admin='admin-0'" lakes_110m.json ne_110m_lakes.shp
ogr2ogr -f GeoJSON -simplify 1 coastline_tiny.json ne_110m_coastline.shp
ogr2ogr -f GeoJSON -simplify 1 -where "scalerank < 2 AND admin='admin-0'" lakes_tiny.json ne_110m_lakes.shp
topojson -o earth-topo.json coastline_50m.json coastline_110m.json lakes_50m.json lakes_110m.json
topojson -o earth-topo-mobile.json coastline_110m.json coastline_tiny.json lakes_110m.json lakes_tiny.json
cp earth-topo*.json <earth-git-repository>/public/data/
Weather data is automatically fetched by the weather service (see WEATHER_SERVICE.md for details).
The weather service:
- Automatically downloads current GFS data from NOAA NOMADS
- Converts GRIB2 to JSON using native JavaScript (no Java required)
- Updates every 6 hours
- Saves data to
public/data/weather/current/
To run the weather service:
npm run weather-service
For manual data fetching (original method), weather data is produced by the Global Forecast System (GFS), operated by the US National Weather Service. Forecasts are produced four times daily and made available for download from NOMADS. The files are in GRIB2 format and contain over 300 records. We need only a few of these records to visualize wind data at a particular isobar.
This project uses M+ FONTS. To reduce download size, a subset font is
constructed out of the unique characters utilized by the site. See the earth/server/font/findChars.js script
for details. Font subsetting is performed by the M+Web FONTS Subsetter, and
the resulting font is placed in earth/public/styles.
Mono Social Icons Font is used for scalable, social networking icons. This can be subsetted using Font Squirrel's WebFont Generator.
Building this project required solutions to some interesting problems. Here are a few:
- The GFS grid has a resolution of 1°. Intermediate points are interpolated in the browser using bilinear interpolation. This operation is quite costly.
- Each type of projection warps and distorts the earth in a particular way, and the degree of distortion must be calculated for each point (x, y) to ensure wind particle paths are rendered correctly. For example, imagine looking at a globe where a wind particle is moving north from the equator. If the particle starts from the center, it will trace a path straight up. However, if the particle starts from the globe's edge, it will trace a path that curves toward the pole. Finite difference approximations are used to estimate this distortion during the interpolation process.
- The SVG map of the earth is overlaid with an HTML5 Canvas, where the animation is drawn. Another HTML5 Canvas sits on top and displays the colored overlay. Both canvases must know where the boundaries of the globe are rendered by the SVG engine, but this pixel-for-pixel information is difficult to obtain directly from the SVG elements. To workaround this problem, the globe's bounding sphere is re-rendered to a detached Canvas element, and the Canvas' pixels operate as a mask to distinguish points that lie outside and inside the globe's bounds.
- Most configuration options are persisted in the hash fragment to allow deep linking and back-button navigation. I use a backbone.js Model to represent the configuration. Changes to the model persist to the hash fragment (and vice versa) and trigger "change" events which flow to other components.
- Components use backbone.js Events to trigger changes in other downstream components. For example, downloading a new layer produces a new grid, which triggers reinterpolation, which in turn triggers a new particle animator. Events flow through the page without much coordination, sometimes causing visual artifacts that (usually) quickly disappear.
- There's gotta be a better way to do this. Any ideas?
Real-time visualization of the day/night terminator line showing which parts of the Earth are currently in daylight or darkness. The calculation uses solar position algorithms to determine sun elevation for each geographic coordinate. See DAY_NIGHT_CALCULATION.md for technical details.
Automatic fetching and display of current GFS weather data with no Java dependency. The weather service uses native JavaScript GRIB2 parsing. See WEATHER_SERVICE.md for architecture and setup details.
Shows current time with UTC/Local toggle, updating every second when day/night overlay is active.
This project includes a Wallpaper Engine version available in the wallpaper-engine/ directory. The wallpaper version:
- Supports all 8 projections with full control via user properties
- Configurable overlays, height levels, and orientation
- Auto-rotation feature (globe spinning)
- Clock visibility control
- Live or bundled data sources
See WALLPAPER_ENGINE.md for details on maintaining and updating the wallpaper version.
Code Sync: The wallpaper version is a minimal wrapper around the core web version. After making changes to core files, run node sync-wallpaper.js to keep versions in sync.
This project is inspired by:
- World Clock - World clock with time zone displays
- The original earth project - Global weather visualization
- The awesome hint.fm wind map and D3.js visualization library
