orbital-engine
    Preparing search index...

    Interface CelestialBody

    interface CelestialBody {
        id: string;
        name: string;
        type:
            | "star"
            | "planet"
            | "dwarf_planet"
            | "moon"
            | "station"
            | "surface_installation"
            | "jump_point"
            | "nav_point"
            | "asteroid"
            | "comet";
        parentId: string
        | null;
        radiusKm: number;
        orbit: OrbitalElements | null;
        fixedPosition: FixedPosition | null;
        coOrbitalWithParent?: boolean;
        rotationPeriodHours?: number;
        color?: string;
        modelUrl?: string;
        textureUrl?: string;
        note?: string;
        wikiSummary?: string;
        wikiUrl?: string;
        beltId?: string;
        atmosphereHeightKm?: number;
        axialTiltDeg?: number;
        pole?: PoleDirection;
        rings?: RingBand[];
    }
    Index
    id: string
    name: string
    type:
        | "star"
        | "planet"
        | "dwarf_planet"
        | "moon"
        | "station"
        | "surface_installation"
        | "jump_point"
        | "nav_point"
        | "asteroid"
        | "comet"
    parentId: string | null

    id of the body this orbits; null only for the system's star

    radiusKm: number

    Physical radius, km — rendering scale only, no bearing on orbital math

    orbit: OrbitalElements | null

    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.

    fixedPosition: FixedPosition | null
    coOrbitalWithParent?: boolean

    True 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.

    rotationPeriodHours?: number

    Rotation 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.

    color?: string

    Real, 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).

    modelUrl?: string

    An 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.

    textureUrl?: string

    An 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.

    note?: string

    Free-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).

    wikiSummary?: string

    A 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.

    wikiUrl?: string

    A 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.

    beltId?: string

    id 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.

    atmosphereHeightKm?: number

    Real 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.

    axialTiltDeg?: number

    Obliquity, 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.

    Direction 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.

    rings?: RingBand[]

    The 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.