Skip to content
github-actions[bot] edited this page Aug 13, 2026 · 1 revision

@elite-dangerous-almanac/core / astro

astro

Astrophysical data and calculations for the Elite Dangerous galaxy.

This entry point re-exports the astro feature area's general API. Every symbol here is also reachable from its own module, so bundlers can drop anything you do not use. The 42-region coordinate lookup stays on ./codex-region-lookup: its map geometry is large enough that native ESM and namespace consumers must opt into it explicitly.

Start with ProceduralSystem — it composes the pieces below into one immutable handle (name ⇄ id64, sector, mass code, hand-authored regions). Drop to the individual functions when you need just one calculation.

A note on the word "region". It means four different things here; the exports are grouped to keep them apart:

None of those is the nebula catalogue — the nebulae themselves, and where they are: nearestNebulae & co. over REAL_NEBULAE, PROCGEN_NEBULAE, and — on their own subpaths, so importing one never bundles the rest — PLANETARY_NEBULAE and ALL_NEBULAE.

Coordinate spaces have different shapes. GalacticPosition is {x, y, z} in light-years with Sol at the origin — what the journal, EDSM and Spansh report, and what findHandAuthoredRegionAt and nearestNebulae take. SectorGridPosition uses {sectorX, sectorY, sectorZ} integer indices on the 1280 ly naming grid, which is what sectorNameFromGridPosition takes. The distinct axis names prevent accidentally passing light-years as sector indices. Convert a real position with sectorGridPositionFromGalacticPosition (or go straight to sectorNameFromGalacticPosition).

findCodexRegionAt reads only {x, z}, because the region map is an X/Z projection; it takes a GalacticPosition as it comes and ignores the y.

Permit locks are six similarly-named lookups; permitLockForSystemName is the one to start from (it answers for both kinds of lock, from a name alone).

Examples

Start here: a name in, an id64 out, and back again.

import { ProceduralSystem } from '@elite-dangerous-almanac/core/astro/procedural-system';

const system = ProceduralSystem.fromName('Synuefe EN-H d11-96');
system?.systemAddress; // -> 3309179996515n
system?.namingRegionName; // -> 'Synuefe'
system?.massCode; // -> 'd'

ProceduralSystem.fromSystemAddress(3309179996515n).name; // -> 'Synuefe EN-H d11-96'

fromName returns null for a string that is not a procedural name — Sol and the other hand-named systems are deliberately outside this type.

The four meanings of "region", all answered for one position — the Pleiades. They disagree, which is the point: each names a different thing.

import { sectorNameFromGalacticPosition } from '@elite-dangerous-almanac/core/astro/galaxy-grid';
import { resolveNamingRegionOrigin } from '@elite-dangerous-almanac/core/astro/naming-region-origins';
import { findHandAuthoredRegionAt } from '@elite-dangerous-almanac/core/astro/hand-authored-regions';
import { findCodexRegionAt } from '@elite-dangerous-almanac/core/astro/codex-region-lookup';

const position = { x: -81.625, y: -151.3125, z: -376.0625 };

sectorNameFromGalacticPosition(position); // -> 'Synuefai'          procedural sector
findHandAuthoredRegionAt(position)?.name; // -> 'Pleiades Sector'   hand-authored region
findCodexRegionAt(position)?.name; // -> 'Inner Orion Spur'  codex region
resolveNamingRegionOrigin('Synuefai')?.x0; // -> 1556480            naming-region origin

And the nebula catalogue, which is none of those — it answers "what is near here":

import { nearestNebulae } from '@elite-dangerous-almanac/core/astro/nebulae';
import { REAL_NEBULAE } from '@elite-dangerous-almanac/core/astro/nebulae-real';

const position = { x: -81.625, y: -151.3125, z: -376.0625 };

nearestNebulae(position, REAL_NEBULAE, 2).map((n) => [n.name, n.distanceLy]);
// -> [['Pleiades', 32.74…], ['Taurus Dark Region', 91.07…]]

The catalogue argument is required here rather than defaulted: ALL_NEBULAE is 431.7 KiB, so importing it must be your decision.

The two coordinate spaces, side by side. Light-years and sector indices are both three numbers, so the axis names are what stop you mixing them up.

import { sectorGridPositionFromGalacticPosition } from '@elite-dangerous-almanac/core/astro/galaxy-grid';
import { sectorNameFromGridPosition } from '@elite-dangerous-almanac/core/astro/sector-name';

// GalacticPosition: light-years from Sol — what a journal or EDSM gives you.
const position = { x: -81.625, y: -151.3125, z: -376.0625 };

// SectorGridPosition: integer indices on the 1280 ly naming grid.
const grid = sectorGridPositionFromGalacticPosition(position);
grid; // -> { sectorX: 38, sectorY: 31, sectorZ: 18 }

sectorNameFromGridPosition(grid); // -> 'Synuefai'

Permit locks come in two kinds, and one lookup answers for both from a name alone.

import { permitLockForSystemName } from '@elite-dangerous-almanac/core/astro/permit-locks';

permitLockForSystemName('Sol')?.kind; // -> 'system'   individually locked
permitLockForSystemName('Col 70 Sector AB-C d1-23')?.kind; // -> 'region'   the whole region is locked
permitLockForSystemName('Synuefe EN-H d11-96'); // -> null       not locked at all

Classes

Interfaces

Type Aliases

Variables

Functions

API

Guides
astro
Classes (1)
ProceduralSystem

Properties

Accessors

Methods

Interfaces (16)
Type Aliases (3)
Variables (11)
Functions (37)
Subpath modules (3)
commodities
Interfaces (1)
Type Aliases (1)
Variables (3)
Functions (3)
equipment
Interfaces (6)
Type Aliases (8)
Variables (3)
Functions (10)
Subpath modules (2)
i18n
Interfaces (1)
Type Aliases (1)
Functions (17)
materials
Enumerations (2)
Interfaces (2)
Type Aliases (2)
Variables (9)
Functions (9)
ships
Classes (3)
BuildMetrics

Methods

LoadoutEditError

Constructors

Properties

Methods

ShipLoadout

Accessors

Methods

Interfaces (125)
Type Aliases (44)
Variables (10)
Functions (85)
Subpath modules (8)

Clone this wiki locally