Files
skills/docs/geospatial/geo/universe/src/packets/packets.md
2026-05-29 08:20:56 +01:00

5.0 KiB
Raw Blame History

Packets

(no submodules)

Purpose

Compact little-endian binary codecs for the two highest-volume payloads in a universe scene: catalogues of observed stars and lists of observed celestial bodies. The codecs trade negligible accuracy for an order-of-magnitude reduction in bytes-on-the-wire compared to a JSON encoding, which matters when streaming thousands of stars to a renderer or syncing scene snapshots over a constrained transport.

Each codec is a pure pair of pack(...) / unpack(...) functions. They are deterministic, allocation-free aside from the one output Uint8Array, and produce identical bytes for identical input regardless of platform endianness because every DataView write is explicit littleEndian = true.

Features

  • packStars / unpackStars — encode StarPacket[] with quantised RA, Dec, magnitude, altitude, azimuth, and a UTF-8 spectral class.
  • packBodies / unpackBodies — encode CelestialBodyPacket[] with full Float64 precision for altitude, azimuth, angular diameter, and apparent magnitude plus UTF-8 name and type.
  • Length-prefixed strings (per-element uint32 length header) so variable-width identifiers are unambiguous.
  • Quantised star fields: RA in 1/10⁷° (uint32), Dec in 1/10⁷° (int32), magnitude × 100 with a +5 offset (uint16), altitude as int8 degrees, azimuth as uint8 (≈1.41° resolution).
  • Empty-array handling: 4-byte count-only buffer.
  • Self-describing count header so a receiver can preallocate.

Usage: Basic Example

import { packStars, unpackStars, type StarPacket } from "@suaveplan/universe";

const stars: StarPacket[] = [
    {
        ra: 10,
        dec: 20,
        magnitude: 3.5,
        altitude: 45,
        azimuth: 180,
        spectralClass: "G2V",
    },
];
const bytes = packStars(stars);
const round = unpackStars(bytes);
// round[0].spectralClass === "G2V"

Usage: Advanced Example

import {
    packBodies,
    packStars,
    unpackBodies,
    unpackStars,
    type CelestialBodyPacket,
    type StarPacket,
} from "@suaveplan/universe";

function snapshot(
    stars: StarPacket[],
    bodies: CelestialBodyPacket[]
): Uint8Array {
    const s = packStars(stars);
    const b = packBodies(bodies);
    const out = new Uint8Array(4 + s.length + 4 + b.length);
    new DataView(out.buffer).setUint32(0, s.length, true);
    out.set(s, 4);
    new DataView(out.buffer).setUint32(4 + s.length, b.length, true);
    out.set(b, 4 + s.length + 4);
    return out;
}

function restore(buf: Uint8Array): {
    stars: StarPacket[];
    bodies: CelestialBodyPacket[];
} {
    const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
    const sLen = view.getUint32(0, true);
    const stars = unpackStars(buf.subarray(4, 4 + sLen));
    const bodies = unpackBodies(buf.subarray(4 + sLen + 4));
    return { stars, bodies };
}

API Reference

interface StarPacket

Field Type Quantisation
ra number uint32, (ra + 180) × 10⁷
dec number int32, dec × 10⁷
magnitude number uint16, (mag + 5) × 100
altitude number int8 degrees
azimuth number uint8, scaled by 255/360
spectralClass string UTF-8, length-prefixed

packStars(stars: StarPacket[]): Uint8Array

Returns the packed buffer. Layout: uint32 count then per-element uint32 specLen headers, then the payload region containing each spectral-class string followed by the 12-byte fixed-width quantised fields.

unpackStars(bytes: Uint8Array): StarPacket[]

Inverse of packStars. Reverses every quantisation; small accuracy losses are inherent (azimuth ≈ ±0.7°, magnitude ≈ ±0.005, RA/Dec ≈ ±5×10⁻⁸°).

interface CelestialBodyPacket

Field Type Encoding
name string UTF-8, length-prefixed
type string UTF-8, length-prefixed
altitude number float64
azimuth number float64
angularDiameterArcmin number float64
apparentMagnitude number float64

packBodies(bodies: CelestialBodyPacket[]): Uint8Array

Layout: uint32 count, per-element uint32 nameLen + uint32 typeLen headers, then per-element name + type bytes followed by 32 bytes of float64 fields.

unpackBodies(bytes: Uint8Array): CelestialBodyPacket[]

Inverse of packBodies — fully lossless for the float64 fields.

Implementation Notes

Star encoding is quantised because telescope-grade precision is not the use case; renderers, mini-maps, and HUDs are. The + 180 offset on RA and + 5 offset on magnitude let the smallest unsigned integer types cover the full physical range without negative-number gymnastics. Body encoding stays at float64 because the population is small (handfuls of objects per scene) and keeping ephemeris precision avoids visible jitter when the same body is repeatedly encoded and decoded over a long-running session. Both codecs use little-endian writes unconditionally so the wire format is platform-independent.