A lightweight, browser-based 3D Earth visualizer with satellites, atmosphere, day/night lighting, and configurable UI controls.
This README documents both what you see on the page and what runs under the hood so you — or other developers — can understand, run, and extend the project.
Open a simple static server in the project folder and navigate to http://localhost:8000
PowerShell (recommended):
# From the project folder (Windows PowerShell)
python -m http.server 8000
# or with Node (if you prefer):
npx http-server -p 8000Then open http://localhost:8000 in your browser.
Files of primary interest:
index.html— application shell and UI markupstyle.css— page and UI stylingscript.js— main application logic (rendering, scene setup, UI wiring)sgp4-worker.js— optional Web Worker for SGP4 satellite propagation
When the app runs, you should see a fullscreen WebGL canvas rendering a 3D planet with:
- The Earth sphere textured with diffuse, bump/normal, and specular maps (day textures).
- A semi-transparent cloud layer that rotates slightly faster than the globe.
- A volumetric-like atmosphere (Rayleigh + Mie approximation) implemented in a three.js
ShaderMaterial(BackSide) that provides a soft scattering effect around the globe. - Day/night shading with a night-lights overlay shader that uses an Earth-night texture and a
u_sunDiruniform to determine the dark side. - A starfield of points placed at large distances to provide depth and a space-like backdrop.
- Satellites represented as GPU points; a specific ISS model placeholder is present (and optionally loaded via GLTF), and many synthetic satellites populate orbit bands for visual density.
- A simple moon placeholder orbiting the scene.
- A directional sun and adaptive ambient lighting to simulate day/night intensity changes.
Controls are available in a compact panel (top-right by default). Controls include toggles for satellites, currents, moon, magnetic field, PBR material, atmosphere on/off, atmosphere exposure (range), night glow (range), fade height, real-time vs. manual time with a datetime input, and a Reset button that restores the initial camera view.
There is also a small, unobtrusive footer credit link: by https://perezchris.netlify.app/.
This section documents the main architectural pieces, libraries used, and non-obvious runtime behavior.
- three.js (r128) — 3D renderer, materials, geometries,
OrbitControls,GLTFLoader. - satellite.js — SGP4 propagation library (used either inside the main thread or inside the worker).
- Optional GLTF ISS model loaded via
GLTFLoaderwhen available. - Textures are loaded from threejs example assets or fallback generated canvases when remote textures fail.
- The project tries to use a Web Worker (
sgp4-worker.js) to offload SGP4 propagation and keep the main thread responsive. - If a Worker cannot be created or
satellite.jsis not available inside it, the code falls back to a main-thread propagation path implemented withsatellite.js. - Propagation updates produce ECI/Geodetic positions which are converted to a normalized, scene-space radius (slightly above the globe) and written into Float32 buffers.
- There are two double-buffers (
prevSatBufferandnextSatBuffer) that hold consecutive position snapshots. The GPU shader interpolates between these via a uniformu_interpto produce smooth motion without updating individual vertices each frame.
- Satellites are rendered as
THREE.Pointswith a customShaderMaterial. - The vertex shader mixes
a_posPrevanda_posNextbyu_interpto compute current position. This allows the worker/main thread to update thenextbuffer periodically while the GPU renders smoothly between updates. - For fallback cases (small synthetic sets), a standard
positionattribute is used.
- The atmosphere is a
ShaderMaterialon a slightly larger sphere (BackSide) with uniforms:u_sunDir— sun direction (ECEF) used to shade the atmosphere and compute day/night transitionsu_cameraPos— used to compute view-dependent effects and camera height fadingu_exposure— controls scattering intensity (driven by therange-atmocontrol)u_betaR,u_betaM,u_g— scattering coefficients and Henyey–Greenstein asymmetry parameteru_fadeHeight— camera altitude fade parameter, controls how the atmosphere fades with camera distanceu_skyColor,u_nightGlow— tint and night glow amplitude
- The shader computes an approximate single-scattering result that blends Rayleigh and Mie contributions, adds limb accents, and applies a gamma curve to presentable color.
- A separate sphere slightly above the globe uses a shader that samples an Earth-night texture and blends it based on the dot product between surface normal and sun direction, producing lighted city areas visible on the night side.
- This shader is additive and respects the day/night weighting calculated from the sun vector.
- Starfield is a
Pointscloud placed far away to simulate space depth; it is static and inexpensive. - Moon is a simple sphere with rough material and is positioned by a crude lunar approximation function for visual effect (not astrodynamically precise).
- Sun is represented by a small emissive sphere plus a
DirectionalLightthat illuminates the globe. The sun position is computed from a simple solar algorithm using Julian dates and rotated into ECEF coordinates.
OrbitControlsprovides the primary camera UX. On init we snapshot the camera position,controls.target, and camera FOV intoinitialCameraState. TheResetbutton restores those values precisely.- There is also an ISS-follow mode that will save the previous camera view and smoothly transition the camera to an orbiting follow of the ISS placeholder — Reset does not automatically cancel follow unless requested.
- Textures have a fallback: if remote textures fail to load, an in-memory canvas is used as a simple substitute to keep visuals functional.
- SGP4 uses a worker when available; otherwise it uses main-thread propagation. If TLE fetch fails, a synthetic set of satellites is created so the scene isn’t empty.
- The renderer is created with
alpha: trueandrenderer.setClearColor(0x000000, 0)so the canvas is transparent and the document body gradient shows through (provides the space background if CSS is present).
tleData— parsed TLE name/two-line entries fetched from CelesTrak (or synthetic fallback)sgp4Worker— optional worker instance used to compute satellite positions off-main-threadprevSatBuffer,nextSatBuffer— Float32Array double-buffers for GPU interpolationtlePoints—THREE.Pointsused to render SGP4-derived satellites witha_posPrev/a_posNextattributessyntheticPoints— fallbackTHREE.Pointsfor synthetic satellite setatmosphere— Mesh with ShaderMaterial for scatteringnightMesh/nightMaterial— sphere + shader for night-lights
Key UI element IDs kept stable for scripting in script.js:
controls— outer controls panelcontrols-hamburger— mobile hamburger togglebtn-follow-iss— follow/stop follow ISS buttonchk-iss— ISS visibility togglechk-satellites— show/hide satelliteschk-currents— ocean currents togglechk-moon— moon togglechk-magnetic— magnetic field togglechk-pbr— PBR Earth material togglerange-atmo— atmosphere exposure sliderchk-atmosphere— atmosphere on/offrange-night— night glow sliderrange-fade— atmosphere fade-height sliderchk-realtime— real-time / manual time toggleinp-datetime— manual datetime input
There is also an on-screen #ui-debug area used during development to display current control values and shader uniform values.
- Start a local static server (see Quick start).
- Open DevTools (F12) and watch the Console: texture, TLE, and worker messages appear there.
- If satellite updates aren’t appearing, check network access to
https://celestrak.com/NORAD/elements/active.txtand whethersgp4-worker.jssuccessfully loaded and posted areadymessage. - To debug shader values, the
#ui-debugpanel displays current slider values and the atmosphere uniforms.
script.jsis intentionally organized as a single-file demo for portability. When making edits:- Keep UI element IDs stable if you modify
index.htmlsoscript.jscan find them without changes. - If you adjust the atmosphere shader uniforms, ensure default values in the
createEarth()function are consistent with the UI ranges.
- Keep UI element IDs stable if you modify
- White page / no background: ensure
style.cssis present and loaded; the renderer is transparent so the document background provides the space gradient. - Worker not launching: check browser security settings (Workers require file served via HTTP(s) rather than
file://). - TLE fetch fails: network access may be blocked; the app falls back to synthetic satellites.
- Replace the synthetic satellites with higher-fidelity groups or filter by NORAD categories.
- Add selectable satellite labels that render as sprites or HTML overlays.
- Improve the moon position and phase math, or add other planetary bodies.
- Move large shader code into
glslfiles and load them for clarity. - Add unit tests around TLE parsing and fallback logic.
index.html # app shell and UI
style.css # page + control styling
script.js # main app (rendering, UI logic, SGP4 integration)
sgp4-worker.js # optional Web Worker for SGP4 propagation
README.md # this file
- This project uses
three.jsandsatellite.js(their licenses apply to their code). - Textures and icons referenced are from public examples (three.js example assets) or generated at runtime as fallbacks.
If you want, I can:
- add a short
CONTRIBUTING.mdwith coding conventions, - extract shader code into dedicated files,
- or generate a
package.jsonand basic dev scripts.
Thank you — tell me which area you want documented more deeply (e.g., the atmosphere math, SGP4 worker internals, or a developer guide for adding new UI controls) and I will expand that section.