API
Everything on this site comes from static JSON files. You can download them directly: no key, no sign-up, and CORS is open, so you can also fetch them from a browser.
Basics
- All files are under
https://eu5db.com/data/. - Each game version has its own folder, named by a version ID such as
1.3.11-0d6cd6f7e3dd. Readversions.jsonto find them.defaultis the latest version. - The format can change when the site is updated. The types at the bottom of this page are always current.
- A path that doesn't exist returns the site's HTML page instead of a 404. Check that the
Content-Typeisapplication/json. - Please be kind to the server: if you need everything, download it once instead of fetching on every request.
Files
| Path | Contents |
|---|---|
versions.json | Every published game version, newest first, and which one is the default. |
<version>/ | Concept types with their counts, plus node and edge totals. |
<version>/ | [id, name, icon] for every node. Use it to search or to list all IDs. |
<version>/ | One summary row per node of a concept type, as shown in the tables. |
<version>/ | Full details for every node in one shard, keyed by node ID. |
<version>/ | Node ID → content hash. The hash changes when the node's content changes. |
<version>/ | Nodes added, removed and changed since the previous version. |
assets/ | Icons and illustrations. The icon fields hold these file names. |
Node IDs
A node ID is concept:key, for example law:administration_of_italian_lands_law. It's the same as the node's page address on this site, /concept/key. Edges and modifiers refer to other nodes by ID.
Finding a node's shard
Nodes are split across 256 files so that a page only downloads a small part of the data. To find which file holds a node, hash its ID with 32-bit FNV-1a, take the result modulo 256, and write it as two lowercase hex digits:
- Start with
hash = 0x811c9dc5. - For each byte of the ID in UTF-8:
hash = (hash XOR byte) × 0x01000193, keeping the low 32 bits. - The shard is
hash mod 256, zero-padded to two hex digits:00toff.
function shardOf(id) {
let hash = 0x811c9dc5;
for (const byte of new TextEncoder().encode(id)) {
hash ^= byte;
hash = Math.imul(hash, 0x01000193) >>> 0;
}
return (hash % 256).toString(16).padStart(2, "0");
}Shard d2 → https://eu5db.com/data/1.3.11-0d6cd6f7e3dd/nodes/d2.json
Example
const base = "https://eu5db.com/data";
const { default: version } = await fetch(`${base}/versions.json`).then((r) => r.json());
const id = "estate_privilege:noble_serfdom_rights";
const shard = await fetch(`${base}/${version}/nodes/${shardOf(id)}.json`).then((r) => r.json());
const node = shard[id];
console.log(node.name, node.modifiers, node.out, node.in);With curl: curl https://eu5db.com/data/1.3.11-0d6cd6f7e3dd/lists/law.json
Types
Optional fields are left out of the JSON when they're empty. body is the parsed game script; see a node file for its shape.
export type Manifest = { version: VersionInfo, concepts: Array<ConceptInfo>, nodeCount: number, edgeCount: number, shardCount: number, diagnostics: Array<DiagnosticCount>, };
export type Index = { nodes: Array<[string, string | null, string | null]>, };
export type ListRow = { id: string, key: string, name?: string, icon?: string, dlc?: string, parent?: string, props?: { [key in string]: JsonValue }, modifiers?: Array<ModifierEntry>,
/**
* Structural outgoing edges (membership, prerequisites, unlocks, event chains).
*/
out?: Array<EdgeRef>, availability?: Array<AvailabilitySource>, };
export type NodeDetail = { out: Array<EdgeRef>, in: Array<EdgeRef>, availability?: Array<AvailabilitySource>, id: string, concept: string, key: string, name?: string, desc?: string,
/**
* Game-relative asset path; replaced by a published file name when assets are exported.
*/
icon?: string,
/**
* Large picture for the top of the page; an asset path like `icon`.
*/
illustration?: string, file: string, line: number, dlc?: string, parent?: string, props?: { [key in string]: JsonValue }, modifiers?: Array<ModifierEntry>, body: Block,
/**
* Localized text for localization keys appearing in the body.
*/
locs?: { [key in string]: string },
/**
* Token → node id for every resolved reference in the body (drives links in the UI).
*/
links?: { [key in string]: string },
/**
* Token → number for references to constant script values, shown next to the name.
*/
values?: { [key in string]: JsonValue }, };
export type EdgeRef = { node: string, kind: EdgeKind, via: string, value?: JsonValue, };
export type EdgeKind = "contains" | "belongs_to" | "requires" | "unlocks" | "triggers" | "grants" | "removes" | "calls" | "modifies" | "references" | "mentions";
export type ModifierEntry = {
/**
* `modifier_type:<key>` node id.
*/
modifier: string, value: JsonValue, scope: Scope,
/**
* Path of the block the entry was found in.
*/
via: string, };
export type AvailabilitySource = {
/**
* Definition declaring these conditions (may be a parent law).
*/
source: string, body: Block, links: { [key in string]: string }, locs: { [key in string]: string }, values: { [key in string]: JsonValue }, };