A lightweight, framework-free Solar System renderer built with Three.js + TypeScript, focused on real scale & orbits, custom GLSL shaders, and a subtle cinematic touch (bloom, lens flare, starfield).
Live demo: https://cmbu.de/
Preview GIF/video will be added once the project is in its final visual state.
This project started as a personal deep dive into modern Web 3D and Three.js internals: custom shaders, post processing, camera control, CSS2D markers, routing, sound, performance tradeoffs, and keeping everything maintainable and typesafe without hiding behind a framework.
It’s a learning project, but it’s built like I want to ship it.
- Framework-free: no React / Vue / Angular. Just Three.js + TS.
- Real scale & orbits: sizes, distances, eccentricity/inclination based on real data (with small pragmatic adjustments where needed for usability).
- Custom shader pipeline for detail and performance:
- multi-caster shadowing (eclipses / occlusion)
- day/night transitions (Earth)
- atmosphere layers (where applicable)
- procedural asteroid impostors (fast belts at scale)
- Cinematic polish (optional): bloom, lens flare, procedural starfield.
- Mobile-friendly controls (orbit + pinch zoom), and responsive UI.
- UI tools: markers, orbits, zoom buttons, fullscreen, sound, and declutter.
- Orbit: Left mouse drag
- Zoom: Mouse wheel
- Pan: not supported (intentionally)
- Orbit: 1 finger drag
- Zoom: 2 finger pinch
- Fullscreen toggle
- Sound toggle + volume slider
- Toggle Orbits
- Toggle Markers
- Zoom In / Zoom Out buttons
- Declutter (auto filtering of markers/orbits)
The simulation can run from real-time up to “1 year per second”.
Available speed presets
- Real-time (1s / s)
- 1 min / s
- 5 min / s
- 15 min / s
- 30 min / s
- 1 h / s
- 3 h / s
- 6 h / s
- 12 h / s
- 1 d / s
- 3 d / s
- 1 w / s
- 2 w / s
- 1 m / s
- 3 m / s
- 6 m / s
- 1 y / s
Planets, dwarf planets, major moons, and belts are included.
Full list
Star & planets
- Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
Dwarf planets / minor planets
- Ceres, Pluto, Haumea, Makemake, Eris
Moons
- Moon (Earth)
- Phobos, Deimos (Mars)
- Io, Europa, Ganymede, Callisto (Jupiter)
- Mimas, Enceladus, Tethys, Dione, Rhea, Titan (Saturn)
- Oberon (Uranus)
- Triton, Proteus, Nereid (Neptune)
- Charon (Pluto)
Belts
- Asteroid Belt
- Kuiper Belt
This project uses multiple custom shaders to keep visuals sharp while staying performant.
-
shader/astronomical.shader.ts
Planet shading + multi-caster shadowing (up to 4 shadow casters, soft edge) for believable eclipses/occlusion. -
shader/astronomical-displacement.shader.ts
Heightmap displacement in the vertex shader (centered displacement) for more believable non-perfect spheres. -
shader/earth.shader.ts
Day/Night blend + night lights + spec map, plus shadow casting. The night side stays alive instead of just going black. -
shader/ring.shader.ts
Ring shadowing: Saturn’s rings darken correctly inside the planet’s shadow cone (with a soft transition). -
shader/asteroid-belt-impostor.shader.ts
Asteroid impostors: point sprites with procedural silhouettes + crater noise + wrapped diffuse + rim lighting.
Orbit parameters are per-asteroid attributes (semi-major/minor, ecc, inclination, phase, angular speed).
Also supports a “bloom mode” discard to keep bloom clean. -
shader/starfield-points.shader.ts
Procedural starfield as crisp, anti-aliased point sprites (HiDPI friendly, no massive HDR sky textures). -
shader/sun.shader.ts+shader/corona.ts
Animated sun surface + corona layer (subtle, distance-aware look). -
shader/mixpass.shader.ts
Bloom compositing pass to mix base + bloom output cleanly.
- TypeScript
- Three.js
- Webpack (dev server + production build)
- Custom GLSL shaders
- CSS2DRenderer for markers
- Post-processing (bloom, compositing, anti-aliasing)
- Custom routing & UI layer (no external UI framework)
- Node.js (recent LTS recommended)
npm installnpm run devnpm run buildnpm run checkThis repo also uses a pre-commit hook (Husky + lint-staged) to keep formatting and linting consistent.
All scripts
{
"start": "npm run dev",
"dev": "webpack serve --config webpack.dev.js",
"build": "webpack --config webpack.prod.js",
"typecheck": "tsc -p tsconfig.json --noEmit",
"lint": "eslint . --ext .ts,.js",
"lint:fix": "eslint . --ext .ts,.js --fix",
"format": "prettier . --check",
"format:write": "prettier . --write",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"check": "npm run lint && npm run format && npm run typecheck",
"check:all": "npm run check && npm run test"
}This repo includes .env.dev and .env.prod.
Production build uses the production env config.
src/application.ts— main orchestrationsrc/manager/— scene/camera/astronomical managerssrc/objects/— bodies (planets, moons, belts)src/shader/— custom shader implementationssrc/ui/— UI renderers, UI manager, statesrc/rendering/— post-processing pipelinesrc/services/— viewport & other service abstractionsdata/— datasets / raw object data
The project uses Vitest for unit testing. The focus is on deterministic logic (state, routing rules, declutter/occlusion helpers), not GPU output.
# run unit tests
npm run test
# watch mode
npm run test:watch
# coverage (text + HTML)
npm run test:coverageMost textures are sourced from (and sometimes adjusted/combined for this project):
- https://www.solarsystemscope.com/textures/
- https://planetpixelemporium.com/planets.html
- https://planet-texture-maps.fandom.com/wiki/Uranus
Some textures are fictional when no high-quality real maps were available.
This project is a personal learning/portfolio project and is not affiliated with NASA/ESA/Three.js.
MIT (see package.json).
Made with a questionable amount of love and shader debugging by Christina Busacker.