GraSim is a real-time N-body gravity sandbox built in C++ with Raylib and compiled to WebAssembly with Emscripten.
Spawn planets, launch stars, watch orbit trails braid together, trigger supernovas, create neutron stars, drop black holes into unstable systems, and let the math make its own disasters. It is not a full game. It is a compact interactive physics toy for making weird little cosmic moments.
GraSim simulates many bodies pulling on each other through softened Newtonian gravity. Bodies can orbit, slingshot, collide, merge, fragment, explode, or collapse into compact remnants depending on the rules currently active.
The fun part is that most of the interesting scenes are not scripted. Binary stars spiral inward because gravity says they should. Big stars go supernova because their mass crosses a threshold. Neutron stars tear apart nearby bodies because their compact gravity creates a Roche-like danger zone. Black holes eat anything that gets too close. White holes, in sandbox mode, shove the entire scene into nonsense.
It is half physics experiment, half screenshot generator.
| Link | Description |
|---|---|
| Play online | Browser build published from docs/ |
main.cpp |
App loop, input, camera, and settings |
simulation.cpp |
Gravity, collisions, supernovas, compact objects, particles |
rendering.cpp |
Body visuals, trails, HUD, gravity field rings |
tests/supernova_rules_test.cpp |
Small regression test for remnant and fragmentation rules |
Every body pulls on every other body. To keep the simulation fast with hundreds of objects, GraSim uses a Barnes-Hut quadtree instead of a naive all-pairs gravity loop.
- Softened Newtonian gravity
- Barnes-Hut approximation for far-away clusters
- Self-force protection so a body is not pulled by a quadtree node containing itself
- Velocity Verlet integration for cleaner orbit behavior
- Adaptive-ish substepping for high-speed real-mode motion
Bodies are not just colored circles anymore. They have types, visual styles, collision behavior, and upgrade paths.
| Body type | Behavior |
|---|---|
| Asteroid | Small jagged debris body; useful for fields and fragments |
| Planet | Default launched body; merges and grows |
| Star | Massive glowing body; can go supernova |
| Neutron star | Tiny dense remnant with bright pulses and tidal disruption |
| Black hole | Compact object that consumes nearby bodies |
| White hole | Sandbox-only repulsor for maximum cosmic nonsense |
Stars that become massive enough can explode. The explosion launches debris, pushes nearby bodies outward, creates a fading shockwave, and may leave a compact remnant.
Current remnant rules:
| Progenitor mass | Result |
|---|---|
< 2000 |
Supernova with no compact remnant |
2000 to 2599 |
Neutron star remnant |
2600+ |
Black hole remnant |
This gives the sim a nicer progression: not every massive star becomes a neutron star, and the biggest collapses become black holes.
GraSim has two physics personalities.
| Mode | Purpose |
|---|---|
| Sandbox | Fixed black holes, white holes, forgiving chaos, dramatic interactions |
| Realism | Moving black holes, no white holes, cleaner compact-object behavior |
Realism mode is still stylized. It is not an astrophysics engine. But it tries harder to avoid toy rules that make no physical sense, especially around compact objects and high-speed impacts.
Collisions can merge bodies, bounce bodies when collision mode is off, or fragment high-speed planet/star impacts in realism mode.
The fragmentation system separates spectacle from simulation:
- Visual debris is mostly cheap
Particledata - Only a small capped number of chunks become real gravity bodies
- Asteroid fragments do not recursively fragment again
- This prevents one small collision from becoming thousands of bodies
That last rule exists because, yes, a small-ish impact once created around 4500 bodies. Science was briefly cancelled.
Black holes are compact eaters with dramatic visuals:
- Dark center
- Orange accretion disk
- Smaller collision/eating radius than their visual presence implies
- Fixed in sandbox mode
- Free-moving in realism mode
The visual radius and collision radius are separate, so black holes can look intense without acting like giant invisible vacuum cleaners.
Neutron stars are compact, bright, and rude.
- Tiny fixed visual size
- Blue-white glow
- Rotating beam-like pulse visuals
- Dense collision behavior
- Tidal disruption of nearby normal bodies
They are meant to feel like dangerous leftovers from supernovas rather than just another kind of star.
GraSim can draw gravity field rings around bodies. These are not required to play with the sim, but they make it easier to understand why bodies start curving, spiraling, or getting ripped out of their paths.
| Input | Action |
|---|---|
| Left drag | Launch a planet |
| Click body | Select a body |
| Right drag | Launch a heavy star |
| Mouse wheel | Zoom toward cursor |
| Middle drag | Pan camera and cancel follow-cam |
[ / ] |
Decrease / increase spawn mass |
A |
Spawn asteroid burst |
B |
Spawn binary stars |
H |
Spawn black hole |
W |
Spawn white hole, sandbox mode only |
N |
Spawn neutron star |
M |
Toggle sandbox / realism mode |
X |
Toggle collisions |
F |
Toggle gravity field rings |
U |
Cycle full / compact / hidden UI |
/ |
Toggle help overlay |
Tab |
Toggle minimap |
L |
Toggle follow-cam for selected body |
Esc |
Clear selected body and follow-cam |
1 |
Slow time, 0.25x |
2 |
Normal time, 1x |
3 |
Fast time, 2x |
4 |
Preset: binary collapse |
5 |
Preset: neutron star feeding |
6 |
Preset: black hole debris field |
7 |
Preset: orbit art cloud |
Space |
Pause / resume |
R |
Reset simulation |
C |
Clear all bodies and effects |
Press B to spawn binary stars and let them spiral. If enough mass merges into one star, it can cross the supernova threshold and leave a neutron star or black hole behind.
Press 4 for a faster binary-collapse preset.
Press N near a dense cluster. Bodies that pass too close can get shredded into hot debris streams.
Press 5 for a neutron-star feeding preset, then use L to ride along with the selected neutron star.
Press H near a messy system and watch the black hole carve through it. In sandbox mode it stays fixed. In realism mode it can drift under gravity.
Press 6 for a black-hole debris preset.
Turn collisions off with X, spawn a lot of bodies, and let the trails draw braided paths across the screen.
Press 7 for an orbit-art preset that starts with collisions off.
Stay in sandbox mode, spawn a white hole with W, then drop black holes and stars nearby. This is not realistic. It is very funny.
GraSim is intentionally small, but the simulation has a few real structure pieces now.
| System | Implementation |
|---|---|
| Rendering | Raylib |
| Web build | Emscripten to WebAssembly |
| Gravity | Barnes-Hut quadtree |
| Integrator | Velocity Verlet |
| Merge collisions | Direct pair checks with radius overlap |
| Elastic collisions | Spatial hashing plus radius checks when merge collisions are off |
| Trails | std::deque for cheap front removal |
| Effects | Lightweight shockwaves and particles |
| Tests | Small direct C++ regression test |
The project is split into three main code areas:
| File | Role |
|---|---|
main.cpp |
Input handling, camera, settings, main loop |
simulation.h / simulation.cpp |
Body data, physics, spawning, collisions, compact object rules |
rendering.h / rendering.cpp |
Drawing bodies, particles, shockwaves, trails, HUD |
GraSim is not trying to be a precise astronomy simulator. It uses real ideas, scaled into a visual sandbox:
- Gravity is softened to avoid infinite forces at tiny distances
- Mass and radius are visual/gameplay scale values, not SI units
- Barnes-Hut trades exact force calculation for speed
- Velocity Verlet improves orbit stability compared with simpler Euler-style updates
- Supernova thresholds are stylized mass ranges
- Neutron star and black hole behavior is inspired by real compact objects, then tuned for interaction
The goal is not perfect realism. The goal is: when something wild happens, it should feel like the rules caused it.
This is the command used for the web build:
$env:EMSDK = "C:\Users\manoj\emsdk"
$env:PATH = "C:\Users\manoj\emsdk;C:\Users\manoj\emsdk\upstream\emscripten;C:\Users\manoj\emsdk\node\20.18.0_64bit\bin;C:\Users\manoj\emsdk\python\3.9.2-nuget_64bit;C:\Users\manoj\emsdk\java\8.152_64bit\bin;" + $env:PATH
cd "C:\Users\manoj\StarDance\GraSim"
& em++ main.cpp simulation.cpp rendering.cpp -o docs/gravity.js "-IC:\raylib\raylib\src" "C:\raylib\raylib\src\libraylib.web.a" -sUSE_GLFW=3 -sASYNCIFY -sALLOW_MEMORY_GROWTH=1 -DPLATFORM_WEB -O2 -std=c++17 2>&1The generated files live in docs/ so GitHub Pages can serve them directly.
The Pages workflow in .github/workflows/pages.yml rebuilds the browser version on every push to main.
The workflow:
- installs Emscripten with
emsdk - builds raylib
5.5forPLATFORM_WEB - compiles
main.cpp,simulation.cpp, andrendering.cppintodocs/gravity.js - uploads
docs/as the GitHub Pages artifact - deploys the artifact through GitHub Pages
In the repository settings, Pages should be set to deploy from GitHub Actions.
If Raylib is available to CMake:
cmake -S . -B build
cmake --build buildFor a fast local C++ check:
g++ -std=c++17 -fsyntax-only main.cpp rendering.cpp simulation.cppThe current tiny regression test checks supernova remnant thresholds, Barnes-Hut approximation rules, and fragmentation caps.
g++ -std=c++17 tests\supernova_rules_test.cpp -o C:\tmp\supernova_rules_test.exe
C:\tmp\supernova_rules_test.exeGraSim is actively evolving. The current focus is making the sim feel more physical without killing the chaotic toybox energy.
Recently added:
- Split simulation, rendering, and main loop into separate files
- Velocity Verlet integration
- Barnes-Hut self-force correctness fix
- Neutron star remnants
- Realism mode
- Visual radius vs collision radius
- Capped high-speed fragmentation
- Compact HUD, help overlay, hidden UI mode, and minimap
- Body selection, follow-cam, selected-body labels, and quick presets
- Regression tests for core rule helpers
Likely next:
- More dramatic accretion behavior near black holes
- Tidal disruption polish
GraSim is for the moment when a simple rule turns into something that looks intentional.
You spawn two stars. They orbit. They merge. The new star explodes. A neutron star survives. It rips through the debris. A black hole drifts nearby and eats the leftovers.
None of that needs to be scripted.
That is the whole point.
