Skip to content
github-actions[bot] edited this page Aug 15, 2026 · 30 revisions

@elite-dangerous-almanac/core / ships

ships

Ship and outfitting data for Elite Dangerous — Frontier's shipyard and outfitting registries.

This entry point re-exports the ships feature area. Every symbol is also reachable from its own module, so bundlers can drop anything you do not use.

Working with a whole build? Start with ShipLoadout — it reads a SLEF export (ShipLoadout.fromSlef) or a journal Loadout event straight out of a player journal (ShipLoadout.fromLoadout), writes either back out (ShipLoadout.toSlefString, ShipLoadout.toLoadoutEvent), lets you fit modules and apply engineering, and answers the questions apps actually ask (ShipLoadout.maxJumpRange, ShipLoadout.powerBudget, ShipLoadout.shieldMetrics, unladenMass, rebuy) — and keeps what a capture said it paid apart from what the build is worth at retail (ShipLoadout.sourcePurchase, a SourcePurchaseRecord). It is the batteries-included facade and pulls in every catalogue; everything below is what it is built from, so drop to the pieces when you need one answer rather than a whole ship.

The area has five layers:

The registries use two distinct Frontier identity spaces. symbol identifies an item — a hull, module, material, micro-resource or commodity — and is what item and journal Item lookups accept. Engineering catalogue entries instead use fdname to identify a recipe, effect or decorative modification. The journal normally writes that id in Engineering.BlueprintName or Engineering.ExperimentalEffect; the few colliding blueprint aliases are resolved for their module by resolveBlueprintForModule. Functions that look up an engineering entry therefore take an fdname, while functions that ask which engineering is available for a module take that module's symbol.

Catalogue containers follow those jobs rather than one universal shape. The identity-bearing entity catalogues — SHIPS and the module catalogues — are readonly arrays because every value carries its own symbol and consumers commonly enumerate or filter them. PRE_ENGINEERED_MODULES is also an array, but it is an enumerable relation: each row joins a base module to engineering and acquisition data rather than identifying a new module with a symbol of its own.

Engineering entities and groups are keyed catalogues: BLUEPRINTS, EXPERIMENTAL_EFFECTS, DECORATIVE_MODIFICATIONS and ENGINEERING_OPTION_GROUPS carry the recipe, effect or group identity in the key rather than repeating it in each value. The separate BLUEPRINT_COSTS and EXPERIMENTAL_EFFECT_COSTS records map those ids to costs; SLOT_RESTRICTION_LABELS maps typed restriction codes to display labels. Use Object.values() or Object.entries() to enumerate any of these keyed structures.

Five fdname maps have public case-insensitive, whitespace-trimming lookups for a caller- or journal-supplied id: getBlueprint, getExperimentalEffect, getDecorativeModification, getBlueprintCosts and getExperimentalEffectCost. Prefer those helpers to direct indexing for external text. Engineering group ids and slot restriction codes are typed keys, so index their maps directly.

Note that a hull's derived figures split by cost: cheap stored values are properties (ShipLoadout.unladenMass), while anything that recomputes or takes options is a method (ShipLoadout.maxJumpRange).

Identity primarily from EDCD FDevIDs (shipyard.csv, outfitting.csv), with supplemental module identities documented in the source record; stats and slot layouts from EDCD/coriolis-data and EDSY. See data/ships/SOURCES.md.

Examples

The whole-build layer. ShipLoadout reads a capture and answers the questions an outfitting screen asks. This is the one to start from, and the one that pulls in every catalogue.

import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';
import type { LoadoutEvent } from '@elite-dangerous-almanac/core/ships/slef';

declare const event: LoadoutEvent;

// Figures below are one build's — a Krait Phantom explorer.
const build = ShipLoadout.fromLoadout(event);
build.maxJumpRange(); // -> 60.5478  (ly)
build.powerBudget().withinBudget; // -> true
build.shieldMetrics()?.strength; // -> 743.12   (MJ)
build.weaponMetrics().total.damagePerSecond; // -> 34

The lookup layer. One small hull catalogue, and 1199 modules split by Frontier's four outfitting categories. Lookups ignore case and surrounding whitespace.

import { getShipBySymbol } from '@elite-dangerous-almanac/core/ships/ships';
import { getModuleBySymbol } from '@elite-dangerous-almanac/core/ships/modules';
import { CORE_MODULES } from '@elite-dangerous-almanac/core/ships/modules-core';

getShipBySymbol('empire_trader')?.name; // -> 'Imperial Clipper'

// Pass a category to bound what you bundle; omit it to search all 1199.
CORE_MODULES.length; // -> 521
getModuleBySymbol('Int_Hyperdrive_Size6_Class5', CORE_MODULES)?.name;
// -> 'Frame Shift Drive'

The catalogues live on their own subpaths (./modules-core, ./modules-internal, ./modules-hardpoint, ./modules-utility, ./modules-all) precisely so importing one does not bundle the rest — ./modules-all is 310.8 KiB.

The data-free layer. Each calculation is its own module over plain constants, so it costs nothing but the function — no catalogue, no build.

import { singleJumpRange } from '@elite-dangerous-almanac/core/ships/jump-range';

singleJumpRange(1237.3, 6.8, {
    optMass: 7528.04,
    maxFuel: 6.8,
    fuelMul: 0.011,
    fuelPower: 2.5025,
    jumpBoost: 10.5, // Guardian FSD Booster
}); // -> 89.4147  (ly)

./power, ./shields, ./armour, ./weapons, ./ammunition and ./resistances are the same shape: pass the constants, get the number.

The slot layer. Slot keys come from the game and are not derivable from position, so read them rather than composing them — and let ShipLoadout.modulesForSlot tell you what actually fits.

import { ShipLoadout } from '@elite-dangerous-almanac/core/ships/ship-loadout';

const build = ShipLoadout.empty('Anaconda');

build.slots('optional').length; // -> 14
build.slots()[0]?.key; // -> the key setModule takes

// Only the modules this mount will accept, by size and restriction.
build.modulesForSlot('FrameShiftDrive');

Classes

Interfaces

Type Aliases

Variables

Functions

API

Guides
astro
Classes (1)
ProceduralSystem

Properties

Accessors

Methods

Interfaces (28)
Type Aliases (6)
Variables (22)
Functions (57)
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