Physical radius, km — rendering scale only, no bearing on orbital math
Exactly one of these is set for a non-star body (neither for the star
itself): orbit when real Keplerian elements are known (the Solar
System validation set — see solarSystemData.ts) and the body should
actually move over time; fixedPosition when only a single real
position snapshot is known (e.g. data extracted from a game's files, or
any other source that gives a single point-in-time position rather than
orbital elements) and the body should stay put rather than animate on a
fabricated orbit.
Both keys are REQUIRED (not optional) specifically so a caller must
write an explicit null for whichever one doesn't apply, rather than
omitting it — omitting fixedPosition used to type-check even though
it meant something real (render.ts's own resolveWorldPosition silently
places a body with neither set at the system's origin, [0,0,0], with
no error or warning). That silent default is exactly the class of bug
validateSystemData (dataContractWarnings.ts) now catches at runtime —
this required-but-nullable shape is the equivalent guard at the type
level, for a TypeScript caller.
OptionalcoTrue when parentId is a labelling/grouping convenience only — this
body doesn't actually orbit that body locally, it shares that body's
OWN orbit around the star at a different point along it. The concrete
real case this exists for: a Lagrange-point station (e.g. a station at
a planet's L4/L5 point) is grouped under its reference planet for
labelling/routing, exactly like a real orbiting station would be, but
it genuinely orbits the star independently, 60°/180° around from the
planet — real millions-of-km away from it, not a nearby local
satellite. Left unset (false) for every ordinary
child (a real moon, a station that really does orbit its planet).
Doesn't affect position math (fixedPosition/orbit already carry the
body's real position regardless) — only camera framing (see
computeFocusForBody in camera.ts), which needs to know "actually
nearby" from "grouped under, but not nearby" to frame a selected
planet without also trying to fit its interplanetary-distance
co-orbital companions into view.
OptionalrotationRotation period on the body's own axis, hours — negative for retrograde
spin (e.g. Venus). Separate from orbital motion entirely: even a
fixedPosition body (no orbital motion, because we only have one
position snapshot for it) can still spin in place — this is what
produces a day/night cycle for a fictional or game-sourced body despite
it not actually orbiting in this engine. Optional; not yet used by the
Solar System validation set.
OptionalcolorReal, documented average colour, when one is actually known (e.g. the Solar System's planets/major moons) — used as-is instead of the generic per-type placeholder colour (see BODY_TYPE_COLOR_FALLBACK in OrbitalSystemScene.tsx). Left unset for anything with no real colour data (e.g. fictional or game-sourced bodies with no published colour source).
OptionalmodelAn optional real 3D model to render instead of this engine's generic per-type placeholder shape (see BodyShape in OrbitalSystemScene.tsx) — e.g. a real ISS model for Earth's ISS entry, instead of the generic station torus. A path to a .glb/.gltf file served from this app's own public/ directory (or any same-origin/CORS-enabled URL); unset for every body by default, so the placeholder shapes remain the norm, not the exception, until a real model is actually supplied for a specific body. Falls back to the placeholder shape if the model fails to load.
OptionaltextureAn optional real surface texture (an equirectangular JPG/PNG) to wrap
around this engine's placeholder sphere, for a 'planet' | 'dwarf_planet'
| 'moon' body with no full 3D model available — real imagery instead
of a flat colour, without claiming actual surface geometry the way
modelUrl does. Ignored for every other body type, and ignored
whenever modelUrl is also set (a full model always wins). Falls back
to the flat-colour placeholder if the texture fails to load.
OptionalnoteFree-text provenance note — where this body's numbers came from and how precise they're meant to be (mean orbital elements are inherently approximate/epoch-dependent; this keeps that honest in the data itself rather than presenting it as more precise than it is).
OptionalwikiA short, human-readable summary of what this body actually IS —
distinct from note, which documents this body's own numeric
provenance (e.g. "radius sourced from X"), not what the place is like.
Consumer-supplied content (the engine has no opinion on where it came
from); optional, and only rendered alongside wikiUrl when present.
OptionalwikiA link to further reading about this body — shown alongside
wikiSummary when both are present. Rendered as a plain link with no
assumption about the target site.
Optionalbeltid of a BeltRegion (see StarSystemData.belts) this body is physically a member of — e.g. a named main-belt asteroid (Ceres, Vesta) that's ALSO plotted as its own tracked body, on top of the belt's own scattered population. Purely a visibility-system hint (see computeVisibleBodyIds in visibility.ts): a belt-linked body doesn't compete individually for a secondary-object slot against unrelated bodies elsewhere in the system — every body sharing the same beltId shares one slot instead, since the belt itself already reads as "there's a population here." Doesn't affect position math or the belt's own particle-cloud rendering at all, only this ranking. Unset for anything not belt-associated.
OptionalatmosphereReal height (km) of this body's visible atmosphere above its surface — e.g. Earth's ~100km (the Kármán line, the conventional "edge of space"), Venus's ~250km (thick, hazy cloud tops visible from space). Drives the translucent atmosphere rim's real size relative to the body's own radius (see BodyShape/PlaceholderBodyShape in OrbitalSystemScene.tsx) rather than an arbitrary fixed ratio applied to every planet regardless of whether it actually has an atmosphere. Unset (no rim rendered) for anything with no real, substantial atmosphere — Mercury, the Moon, and the dwarf planets in this dataset all genuinely have none/negligible. Deliberately not set for the gas/ice giants either: they have no real surface/atmosphere boundary to draw a rim around at all, so one wouldn't represent anything real about them.
OptionalaxialObliquity, degrees — the tilt of this body's equator against its own
orbit (Saturn 26.7°, Uranus a near-sideways 97.8°). On its own it says
how FAR the equator tilts but not which WAY, so it's only a fallback
for the ring plane when pole isn't set: the equator is then taken as
tilted by this much with its ascending node on the reference frame's
+x axis — the same convention as an orbit's inclination, so a moon with
inclinationDeg equal to this and longitudeOfAscendingNodeDeg 0 lies
exactly in the ring plane. Unset (and no pole) means 0.
OptionalpoleDirection of the body's spin axis — the pole its rotation turns
anticlockwise about (the right-hand rule), in the system's reference
frame (see PoleDirection). Defines the equatorial plane its rings
are drawn in, and it's what a moon's orbit.referencePlanePole should
match when its elements are quoted against this body's equator. For a
retrograde rotator (Uranus, Pluto) this is the opposite end from the
IAU's "north" pole for planets. Takes precedence over axialTiltDeg.
OptionalringsThe body's own ring system — part of the body, not a separate object:
drawn with it, moving with it, selected and framed with it, in its
equatorial plane (see pole, or axialTiltDeg as a fallback). Radii are real km from the
body's centre and scale with the body as it's rendered, so a ring stays
in proportion even while a small body is floored to a minimum on-screen
size (see pixelFloor.ts). For a population that surrounds a star, or a
large belt a planet merely sits inside, use a BeltRegion instead —
those are objects in their own right.
id of the body this orbits; null only for the system's star