Introduction
An ORION mod is a folder of JSON files and pictures that adds to or replaces the game's content; mods never run code. You build one in a text editor, test it from the game's MODS page, and share it as a folder or through the Steam Workshop.
This guide covers mod API 1.0.0 and ORION 0.3.x. Every example in it
is one of the example mods that ship in docs/examples/,
which the test suite loads on every build.
What a mod can change:
- Rules and content: technologies, ship hulls and modules, stations and buildings, planet buildings and planet types, empires, crisis factions and crisis scenarios, events and anomalies, national campaigns, governor traits, politics (governments, faiths, ruler traits, doctrines), ethics and AI personality.
- Tuning tables: combat, research, megastructures, espionage, special projects, federations, biowarfare, startup focuses, star names, galaxy generation.
- Presentation: tech icons, empire emblems, map and outliner icons, ship and station models (shipsets), weapon, beam and shield looks, hints, Command Guide text and tutorial text.
What needs code and cannot be modded yet: new portrait parts, sound, new ship classes, new resources, new agreement kinds, new victory types and translations.
How to read this guide: build the quick-start mod first, then jump to the worked example closest to what you want to make. The reference sections at the end list every folder, field rule and limit.
Quick start: your first mod in ten minutes
This mod halves the research cost of Energy Grid, the first economy
tech. It is the shipped example
balance-cheaper-energy-grid.
- Find the Mods folder. In the shipped game it is
Mods/inside the save folder (%LOCALAPPDATA%/Chronos/<game>/Saves/Steam/<your Steam id>/when signed in to Steam); in ChronosEditor it is<project>/Library/Saves/Mods/. With no mods installed, the MODS page shows the exact path, and so does the hint on its REFRESH button. - Make the folder
Mods/cheaper-energy-grid/. - Write the manifest
orion.mod.jsonin it:
{
"id": "com.yourname.cheaper-energy-grid",
"name": "Cheaper Energy Grid",
"author": "Your name",
"description": "Energy Grid costs half as much research.",
"version": "1.0.0",
"gameVersion": ">=0.3.0 <0.4.0",
"modApiVersion": "^1.0.0",
"contentPath": "content",
"dependencies": []
}- Copy the base file into the same path under
content/:content/Definitions/Techs/Shared/Physics/Economy/1000_energy_grid.json. In a ChronosEditor project the base definitions are inassets/ChronosSimulationCore/content/; the example folder already holds the edited copy. - Change one number: set
"ResearchCost": 1000. Leave every other field as it was, because a file with the same path replaces the base file completely. - Enable it. Open MODS from the main menu, press REFRESH, select Cheaper Energy Grid and press ENABLE. New mods are never enabled on their own.
- Restart ORION. A changed mod set applies after a restart. Start a new game: Energy Grid now costs 1,000.
If the mod does not appear or shows a red line under its name, see Troubleshooting below. Once it works, you can publish it with PUBLISH TO WORKSHOP (Steam Workshop section).
The mod folder and its manifest
A mod is one folder directly inside the Mods folder, holding a manifest and a content folder laid out like the game's own.
my-mod/
orion.mod.json the manifest (required)
preview.png Workshop image: .png, .jpg, .jpeg or .gif, under 1 MB (needed to publish)
content/ JSON content, same folders as the game's content
Definitions/ techs, units, empires, events, tuning tables ...
UI/ hint, Command Guide and tutorial text
Visuals/ weapon looks and shipsets
Resources/ pictures, models and sounds, same paths as StreamingAssets/Resources
orion.workshop.json written by the game when you publish; keep itOnly .json files under content/ are read as
data, and only the asset types in the Reference section are read from
Resources/; anything else (notes, source art) is ignored
and never uploaded. Neither the folder nor anything in it may be a
symbolic link.
orion.mod.json
{
"id": "com.yourname.better-lasers",
"name": "Better Lasers",
"author": "Your name",
"description": "What the mod changes, in a sentence or two. It becomes the Workshop description.",
"version": "1.2.0",
"gameVersion": ">=0.3.0 <0.4.0",
"modApiVersion": "^1.0.0",
"contentPath": "content",
"dependencies": [ { "id": "com.someone.base-pack", "version": ">=2.0.0" } ]
}| Field | Required | Rules |
|---|---|---|
id |
yes | 3 to 128 characters: letters, digits, .,
_, -; starts and ends with a letter or digit;
compared without case. Never change it once published. A reverse-domain
name (com.yourname.mod) avoids clashes. |
name |
yes | Up to 160 characters. It is the Workshop title, which Steam limits to 128 bytes (accented letters count double), so PUBLISH refuses a longer one. |
author |
no | Up to 160 characters. |
description |
no | Up to 4,000 characters. |
version |
yes | A version such as 1.2.0 (1 means 1.0.0;
-beta.1 and +build suffixes allowed). Raise it
with every published change: multiplayer compares it exactly. |
gameVersion |
yes | The ORION versions the mod supports, as a range. The current game is 0.3.0. |
modApiVersion |
yes | The mod API range; the current API is 1.0.0, so use
^1.0.0. |
contentPath |
no | The content folder, relative to the manifest, inside the mod folder.
Default content. |
dependencies |
no | Up to 256 mods, each "some.id" (any version) or
{ "id": "some.id", "version": ">=2.0.0" }. They load
before this mod. |
Field names are not case-sensitive, a field may appear only once, and the manifest must be under 1 MB.
Version ranges
| Write | Means |
|---|---|
>=0.3.0 <0.4.0 |
every comparator must match (space or comma between them) |
^1.0.0 |
1.0.0 up to, but not including, 2.0.0 (the first non-zero part may not rise) |
~0.3.1 |
0.3.1 up to, but not including, 0.4.0 |
0.3 or 0.3.x |
any 0.3 version |
1.2.3 |
exactly 1.2.3 |
* |
any version |
>=0.3.0 <0.4.0 || >=0.5.0 |
either range |
You can also write a range as an object,
"gameVersion": { "min": "0.3.0", "max": "0.3.9" } (max
included), or { "exact": "0.3.0" }. A mod whose ranges do
not match the running game shows as invalid and does not load.
Content limits
A mod's content may hold up to 10,000 JSON files and 20,000 entries in all, each JSON file up to 16 MB and 256 MB of JSON in total.
How the game combines content
The game reads the base content first, then each enabled mod in load order; when two sources define the same thing, the later one wins the whole thing. There is no field-by-field merge, except in tuning tables.
Load order
- Content loads once, when the game starts. Changing the mod set takes a restart (the MODS page says CHANGES APPLY AFTER RESTART).
- Mods whose dependencies are missing, disabled, the wrong version or blocked are dropped, repeatedly, until the set is stable.
- The rest are sorted so every dependency loads before the mods that need it. Among mods that do not depend on each other, your order on the MODS page (MOVE UP, MOVE DOWN) decides, then the id.
- Mods caught in a dependency loop are blocked.
Three ways a mod changes content
| Rule | How | Example |
|---|---|---|
| Same path replaces | A file with the same path under content/ as a base or
earlier mod file replaces it whole. Works for definitions, events,
tuning tables, UI/, Visuals/ and
pictures. |
balance-cheaper-energy-grid |
| Same id replaces | A definition in a new file with the id of an existing one
(TechId, FactionId, TypeId and so
on) replaces that definition. A warning is logged. |
a file with "TechId": 1000 anywhere under
Definitions/Techs/ |
| New content adds | A definition with a new Key, or an unused id, is
added. |
new-tech-mantle-taps |
The MODS page lists, for a selected mod, how many base files it REPLACES by path and which other mods it overrides.
Keys instead of numbers
Give new content a Key and leave its id out; the game
assigns the id when it loads, so two mods never pick the same
number.
- A Key is 2 to 96 letters, digits,
.,_or-, starting with a letter or digit, and is compared without case. Start it with your mod's name (yourmod.deep_lenses). - Never change a published Key: saves and other mods refer to it.
- Automatic ids follow the Keys in alphabetical order, not the load order, so the same set of mods always gives the same ids, and reordering unrelated mods keeps saves loading.
- Two definitions with the same Key but different ids fail the load.
- To replace someone else's keyed definition, use its Key and its id; a Key alone only matches a definition that carries both.
| Kind | Keys | Automatic ids from |
|---|---|---|
| Technologies | yes | 20000 |
| Ship modules | yes | 100 |
| Empires | yes | 7000 |
| Governor traits | yes | 200 |
| National campaigns | yes | 100 |
| Units, stations and buildings, planet buildings, planet types, crisis factions | a Key for others to refer to | none: give the numeric id |
| Politics (governments, faiths, ruler traits, doctrines) | yes, or the name | after the highest id |
| Crisis scenarios | yes | 16 |
| Shipsets | yes | 100 |
| Events | no: the id string |
a second file with the same id fails; replace an event
by path |
Referring to other content
Reference fields take a Key, a name or a number. A name is the
display name in lower case with every run of other characters turned
into _: "Xenon Harvesting" is
xenon_harvesting, "Laser I" is laser_i. A name
that matches nothing, or two definitions, fails the load with the file
and field named; give the target a Key and use that.
| Definition | Fields that take Keys and names |
|---|---|
| Technology | Prerequisites, UnlocksUnitTypes,
UnlocksBuildingTypes, UnlocksPlanetBuildings,
UnlocksModules, UnitUpgradeFrom,
UnitUpgradeTo, FxLike |
| Module | RequiredBuildingTypes |
| Empire, crisis faction | StartingTechs, ExclusiveTechIds,
StarterUnits[].TypeId, ConstructorUnitTypeId,
ResearchUnitTypeId, ColonyUnitTypeId,
PreferredPlanetType, StartingBuildings,
MineBuildingTypeId, FortressTypeId |
| Planet building | FactionId |
| Event effects | tech in grant_tech and
tech_researched; building,
planet_type, unit_type,
crisis_type, district |
Code names instead of numbers
Fields that hold a code (a category, a modifier, an ethic, a colour)
take the code's name as well. Case, spaces, _ and
- do not matter: "EnergyIncome" and
"energy_income" are the same. A wrong name fails the load
and lists the valid ones.
{ "Category": "Physics", "ModifierTypes": [ "EnergyIncome", "ResearchSpeed" ], "ModifierValues": [ 10, 5 ] }The base game's own files use the names, so a copied base file
already reads well; the schemas in docs/modding/schemas/
list them for your editor.
Tuning tables merge by field
A tuning table (combat.json, research.json
and the others in the worked examples) is replaced by path, but fields
you leave out keep the shipped value, so a mod can change one number. A
list replaces the whole list. An unknown field, or a value out of range,
fails the load.
Worked examples
Each example below is a complete mod from
docs/examples/; copy its folder into your Mods folder,
enable it, and change it from there. Only the interesting fields are
shown; the example files carry the rest.
| Example | What it shows | Files under content/ |
|---|---|---|
minimal-orion-mod |
A manifest that loads and changes nothing | README.txt |
balance-cheaper-energy-grid |
Replace a base file by its path | Definitions/Techs/Shared/Physics/Economy/1000_energy_grid.json |
new-tech-mantle-taps |
A keyed tech with a named prerequisite and its own icon | Definitions/Techs/mantle_taps.json,
Resources/Tech_Icons/example/mantle_taps.png |
new-weapon-scatter-cannon |
A weapon tech that borrows a stock look (FxLike) |
Definitions/Techs/scatter_cannon.json |
new-empire-halvard-compact |
A keyed empire with named starting techs | Definitions/Factions/halvard_compact.json |
new-event-silent-buoy |
A survey event with two choices that grants a tech | Definitions/Events/example_the_silent_buoy.json |
new-politics-tide-wardens |
A new government and a new faith | Definitions/Politics/Governments/tide_wardens.json,
Definitions/Politics/Faiths/the_long_tide.json |
new-crisis-ash-tide |
A new crisis built on a base behavior | Definitions/CrisisScenarios/ash_tide.json |
art-energy-grid-icon |
Replace a picture; looks-only, multiplayer-safe | Resources/Tech_Icons/physics/001_energy_grid.png |
visual-weapon-looks |
Retune how weapons look | Visuals/Weapons/looks.json |
new-shipset-wedge |
A shipset with its own hull models | Visuals/Shipsets/wedge.json,
Resources/Shipsets/wedge/wedge.glb |
Balance tweak: change a base definition
Copy the base file to the same path under content/ and
edit it. The whole file is replaced, so keep every field. This is the
quick-start mod: Energy Grid's ResearchCost goes from 2000
to 1000.
A change to one number in a tuning table is even smaller, because fields you leave out keep their shipped value:
{ "BuildingFireRate": 20 }Saved as content/Definitions/Combat/combat.json, this
makes a station's base gun fire every 20 ticks instead of 10. Intervals
are in ticks or months, so a larger number is slower. A list replaces
the whole list; an unknown field or a value out of range fails the load
and names the file and field.
Tuning file under Definitions/ |
What it tunes |
|---|---|
Combat/combat.json |
damage by weapon and hull class, evasion, tracking, station salvo
interval (BuildingFireRate), disengage chance, shield
regeneration, star combat |
Research/research.json |
techs needed per tier, influence cost of a redraw |
Megastructures/megastructures.json |
the six megastructures: stages, time, cost, output (retune only) |
StartupFocuses/startup_focuses.json |
the startup focuses, ids 0, 1, 2 in order; add one by adding an entry |
Names/star_names.json |
star names and catalog prefixes |
Espionage/espionage.json |
spy capacity and upkeep, chances, each assignment's intel, cost and months |
SpecialProjects/special_projects.json |
special project costs and times |
Federation/federation.json |
charter and project votes and cooldowns, the two federation projects |
Biowarfare/biowarfare.json |
the techs and building biowarfare needs, bay and payload limits, natural strains |
GalaxyConfig.json at the root of content/
tunes galaxy generation the same way.
A new technology
Give new content a Key and leave the numeric id out; the
game assigns the id when it loads. Refer to other techs by Key or by
name ("Xenon Harvesting" is
xenon_harvesting).
{
"Key": "example.mantle_taps",
"TechName": "Mantle Taps",
"Description": "Taps heat from the mantle of mined worlds.",
"IconPath": "Tech_Icons/example/mantle_taps",
"Category": "Physics",
"Branch": "Economy",
"Tier": 3,
"Weight": 40,
"ResearchCost": 9000,
"Prerequisites": [ "xenon_harvesting" ]
}| Field | Meaning |
|---|---|
Category |
Physics, Society or
Engineering: the research field that deals it |
Branch |
The column on the research screens; copy one from a base tech of the
same field (Economy, Weapons,
Drives) |
Tier |
1 to 5; dealt once enough of the tier below is researched (default 1) |
Weight |
How often it is dealt; 100 is average, 0 means only events or starting techs grant it (default 100) |
IconPath |
A picture under content/Resources/, without
.png |
StartsResearched |
true gives it to every new empire |
SensorPermille |
Adds to the monthly chance of finding stealthed fleets |
Effects (ModifierTypes with ModifierValues,
the Unlocks… lists, EntityModifiers) are
easiest to copy from a base tech that does something similar. Code
fields take names:
"ModifierTypes": [ "EnergyIncome", "ResearchSpeed" ].
A new weapon
A weapon is a tech with IsShipComponent: true and entity
modifiers on the hull it arms. FxLike borrows the look of a
stock weapon, so it fires, glows and hits like that tech with your
numbers:
{
"Key": "example.scatter_cannon",
"TechName": "Scatter Cannon",
"Category": "Engineering", "Branch": "Materials", "Tier": 4,
"ResearchCost": 33000,
"Prerequisites": [ "revolver_autoloaders" ],
"IsShipComponent": true,
"EntityModifiers": [
{ "TargetKind": "Unit", "TargetId": 100, "ModType": "Weapon", "ModValue": 2900 },
{ "TargetKind": "Unit", "TargetId": 100, "ModType": "FireRate", "ModValue": 5 }
],
"WeaponCategory": "Kinetic",
"WeaponRange": 27,
"FxLike": "rotary_mass_drivers"
}A new empire
An empire is a Definitions/Factions/ file. Starting
techs, unit types and buildings take names or Keys; ethics and colour
take code names.
{
"Key": "example.halvard_compact",
"FactionName": "Halvard Compact",
"Description": "A league of shipwright guilds that trades first and fights only for its lanes.",
"Color": "teal",
"LeaderName": "Speaker Ilsa Halvard",
"Ethics": [ { "Id": "Xenophile", "Level": "Held" }, { "Id": "Materialist", "Level": "Held" } ],
"Government": "Free Republic",
"RulerTrait": "Builder",
"ShipSet": "Shipset_7",
"StarterUnits": [ { "TypeId": 6, "Count": 1 }, { "TypeId": 1, "Count": 1 }, { "TypeId": 2, "Count": 4 } ],
"StartingTechs": [ "diplomatic_corps", "laser_i", "zero_g_combat_vessels", "bulk_freighters" ]
}The Ai… fields (0 to 1000) shape how the AI plays the
empire; the …Multiplier fields (1000 = 100%) scale building
and unit health, cost and output. ShipPrefix sets the
ship-name prefix (up to 5 letters). The emblem goes in
Resources/Empire_Icons/<FactionName>/emblem_outline_ui.png
as a white outline; the game tints it. A Species block
picks the ruler's face from the built-in portrait parts, the same design
the Empire Creator saves; copy one from a saved design.
An event
An event is a small story graph in Definitions/Events/:
an entry that decides when it can fire,
targets, and steps that are choices or
ends.
{
"schema_version": 1,
"id": "example_the_silent_buoy",
"start": "discovery",
"entry": { "scope": "survey", "repeat": "once_per_empire", "weight": 10,
"pool": "survey_discoveries", "pool_cooldown_ticks": 540 },
"targets": { "site": { "required": true } },
"steps": {
"discovery": {
"kind": "choice",
"title": "The Silent Buoy",
"text": "The survey of {system_name} finds a navigation buoy in a slow orbit of {planet_name}.",
"fallback": "leave_it",
"choices": [
{ "id": "recover", "text": "Recover the buoy for study", "preview": "Stability +5. Unlock Xenon Harvesting.",
"ai_weight": 2,
"effects": [ { "type": "increase_stability", "amount": 5 }, { "type": "grant_tech", "tech": "xenon_harvesting" } ],
"next": "recovered" },
{ "id": "leave_it", "text": "Log it and move on", "preview": "Approval +5.", "ai_weight": 1,
"effects": [ { "type": "increase_approval", "amount": 5 } ], "next": "logged" }
]
},
"recovered": { "kind": "end", "title": "A Buoy in the Hangar", "text": "Engineers find no fault." },
"logged": { "kind": "end", "title": "A Dark Lane", "text": "The buoy stays where it is, silent." }
}
}fallback is the choice taken when nobody decides;
ai_weight sets how AI empires choose. Effects and
conditions that take a building, planet type, unit type, crisis type or
district accept names.
Politics: a government and a faith
Governments, faiths, ruler traits and doctrines are one file each. A
new Key adds one; a base Id retunes it.
{
"Key": "example.tide_wardens",
"Name": "Tide Wardens",
"Form": "Assembly",
"Succession": "Elective",
"Effects": "M+15 E+10",
"Ai": "Eco+40 Dip+40",
"Affinity": { "Xenophile": 2, "Pacifist": 2, "Militarist": -2 },
"StartingLaws": [ "open_borders", "free_market", "defensive_doctrine" ],
"Blurb": "Elected wardens keep the trade lanes open and the guns cold."
}Effectstokens:E,M,A,S(energy, mineral, alloy, science income in tenths of a percent, soE+20is +2%),Inf(influence a month),StabandAppr(out of 1000),Cap(fleet capacity).Aitokens (required):Mil,Exp,Tech,Eco,Dip,Tre,Risk,Trade,Hos,Opn,Ord,Cau.Affinityruns from −9 to 9 per ethic; empires start with the government and faith that fit their ethics best.FormisSovereign,Council,AssemblyorUnion;SuccessionisHereditary,Appointed,Elective,CouncilChoice,MartialorSeniority.
A faith is shorter:
{ "Key": "example.the_long_tide", "Name": "The Long Tide", "Effects": "E+15 S+10", "Ai": "Dip+50 Eco+20", "Affinity": { "Spiritualist": 1, "Pacifist": 2, "Xenophile": 1 } }.
Policies, government forms and the ten ethics can be retuned by
Id but not added.
A crisis
A new crisis names the base behavior it plays like; the rest is yours.
{
"Key": "example.ash_tide",
"Name": "The Ash Tide",
"Behavior": "GlassPlague",
"WarningMonths": 36,
"BaseBudget": 0, "BaseWork": 160,
"SiteCount": 4, "WaveInterval": 18, "HoldMonths": 6, "SpreadInterval": 4,
"Weight": 80,
"Variants": [ "A dead star sheds a cloud of reactive ash across the lanes." ]
}| Behavior | Ends when | Needs ActorFaction |
|---|---|---|
ConvertedSignal, RogueFoundries |
its fleets and sites are destroyed | yes |
GlassPlague |
shared research and engineering are complete | no |
HyperlaneResonance |
shared research is done and every site disabled, or 12 years pass | no |
DevourerMigration,
DimensionalFracture |
its fleets and sites are destroyed; it damages worlds | yes |
Dimming |
shared research is done and every site disabled; it drains output | no |
CustodianUltimatum |
its fleets are destroyed, or every empire complies and the work is done | optional |
WarningMonths is 36 for a mid-game crisis and 60 for a
late one ("Late": true). Weight (50 to 150)
sets how often it is picked against the others of its era.
Art: replace a picture
Put a file under content/Resources/ with the same path
as the base picture. art-energy-grid-icon replaces one tech
icon with Resources/Tech_Icons/physics/001_energy_grid.png
and has no JSON at all, so it is looks-only: players with and without it
can play multiplayer together.
Interface text
Hints, Command Guide text and tutorial lessons are overridden entry
by entry from content/UI/. The current text to copy from is
in docs/modding/reference/ (hints.json,
guide-text.json, onboarding.json).
{ "Exact": { "research_redraw": { "Title": "REDRAW", "Body": "Deal new options for 50 influence." } } }Saved as content/UI/Hints/redraw.json.
Prefixes matches every element whose name starts with a
string; Detail adds a second paragraph.
Weapon and shield looks
{
"Kinetic": { "railgun": { "Rounds": 3, "Interval": 0.08, "Pellet": 0.9, "Spread": 0.14, "Tracking": 0.55, "Speed": 1.1, "Tracer": 1.2 } },
"Beam": { "Laser I": { "Width": 1.1, "Duration": 1.0, "Core": 0.09, "Halo": 0.16, "Power": 2.5, "Pattern": 1,
"Frequency": 2.0, "Speed": 5, "Modulation": 0.5, "Color": [0.2, 1.0, 0.35] } },
"Shield": { "deflector_shields": { "Style": 2, "Color": [0.4, 0.7, 1.0] } }
}Saved under content/Visuals/Weapons/. Entries are keyed
by TechId, Key or name. Shield Style is 0 to 13. Every
stock value is in docs/modding/reference/visuals.json.
A shipset
{
"Key": "example.wedge",
"Name": "Wedge",
"Fallback": 1,
"Units": {
"2": { "Model": "Resources/Shipsets/wedge/wedge.glb", "Center": [0, 0, 0], "Size": [2.0, 0.6, 4.0] },
"3": { "Model": "Resources/Shipsets/wedge/wedge.glb", "Center": [0, 0, 0], "Size": [2.0, 0.6, 4.0] }
}
}- Saved under
content/Visuals/Shipsets/; the model goes incontent/Resources/Shipsets/wedge/wedge.glb. UnitsandBuildingsare keyed by unit and stationTypeId; whatever the set leaves out comes from stock setFallback(1 to 7, 9 or 10).Sizeis the hull's bounding box andCenterits middle; a building entry takesScaleandRadius;AuthoredUv: truekeeps the model's own texture layout.- An empire uses it with
"ShipSet": "example.wedge". - The engine builds lower-detail versions for distant views. To supply
your own, name meshes
Hull_LOD1,Hull_LOD2inside the file, or shipwedge_LOD1.glb,wedge_LOD2.glbnext towedge.glb.
Publishing to the Steam Workshop
You publish from inside ORION: select a local mod on the MODS page and press PUBLISH TO WORKSHOP. Steam must be running, and you can only publish mods from your own Mods folder, never a subscribed copy.
First publish
- Put
preview.png(or.jpg,.jpeg,.gif, under 1 MB) next toorion.mod.json. A new item needs one; an update without one keeps the current image. - Select the mod in MODS and press PUBLISH TO WORKSHOP. The page checks the mod first and says what stops it: manifest problems, a duplicate id, a title over 128 bytes, a missing or too large preview, or no content at all.
- Choose who can see it: PRIVATE (the default), FRIENDS, UNLISTED or PUBLIC. Start private or unlisted while you test.
- Write a change note (up to 8,000 characters; empty becomes "Version 1.2.0").
- Press PUBLISH. The game uploads a clean copy, then shows PUBLISHED. An upload cannot be cancelled once it starts.
- Steam keeps a new item hidden until you accept the Workshop legal agreement. When Steam asks for it, the game opens the item page once; the Terms button opens the agreement too.
What goes up
The game stages a copy in its own folder and uploads only:
orion.mod.json- every
.jsonfile in the content folder - assets under
content/Resources/within their size caps - the preview image
orion.branches.json, only when you set a branch range
Your orion.workshop.json, notes, source art and anything
else beside the mod stay on your disk.
| Workshop field | Comes from |
|---|---|
| Title | the manifest name (at most 128 UTF-8 bytes) |
| Description | the manifest description (or the name), followed by
lines for the mod id, version, supported ORION versions and
dependencies; at most 8,000 bytes |
| Metadata | the id, version, game and mod API ranges and dependencies, used by the game |
| Tags | the content it touches (below), plus the game version
(ORION 0.3) |
| Visibility | what you choose on the publish panel, remembered for the next update |
Tags
Tags come from the paths your content uses, so players can filter for them:
| Content path | Tag |
|---|---|
Definitions/Techs/, Research/ |
Technology |
Definitions/Factions/,
StartupFocuses/ |
Empires |
Units/, Modules/,
Minefields/, Combat/ |
Ships |
Buildings/, PlanetBuildings/,
Megastructures/ |
Buildings |
PlanetTypes/ |
Planets |
Events/, SpecialProjects/,
Biowarfare/ |
Events |
Crisis/, CrisisScenarios/ |
Crises |
Campaigns/, Politics/,
Ethics/ |
Politics |
Traits/ |
Leaders |
Diplomacy/, Espionage/,
Federation/ |
Diplomacy |
GalaxyConfig.json, Names/ |
Galaxy |
AI/ |
Balance |
UI/ |
Interface |
Visuals/, any picture or model |
Visuals |
You may add Balance, Overhaul,
Translation or Fixes yourself in
orion.workshop.json; other tags are dropped.
Updating
The first publish writes the item id into
orion.workshop.json. Every later publish from the same
folder updates that item, and the button reads UPDATE WORKSHOP ITEM.
Keep the file, never edit its PublishedFileId, and raise
version in the manifest before each update.
{
"PublishedFileId": 3412345678,
"Visibility": "unlisted",
"Tags": [ "Balance" ],
"MinGameBranch": "",
"MaxGameBranch": "",
"LastPublishedVersion": "1.2.0",
"LastPublishedUtc": "2026-11-03T20:00:00Z"
}If the first upload fails after Steam created the item, the id is already saved, so the next attempt updates the same item instead of making a second one.
Tying a version to Steam branches
Set MinGameBranch and MaxGameBranch (branch
names) in orion.workshop.json before publishing, and Steam
serves that version only to players on those branches. Leave them empty
to support every branch. The range also travels with the item as
orion.branches.json; a player outside it sees an amber note
on the MODS page ("made for branch beta, a newer build than yours"), but
the mod still loads.
Subscribing and working on your own item
- Subscribed items appear on the MODS page once Steam has downloaded them; until then they read DOWNLOAD or UPDATING, and DOWNLOAD asks Steam for the files. OPEN ITEM shows the item in Steam.
- Subscribed mods are enabled and ordered like local ones; nothing is enabled on its own.
- If you subscribe to your own item, the MODS page uses your local folder and marks the Workshop copy LOCAL COPY USED, so you keep working on the files you edit.
Multiplayer and saves
Every player in a game must run the same rule-changing mods, at the same versions, in the same order; mods that only change looks are exempt.
What must match
The game builds a fingerprint of the active mods: for each mod in
load order its id, its version and the bytes of every JSON file outside
UI/, Visuals/ and Resources/. A
lobby only lets you in when your fingerprint, the game build and the
combined content all match the host's.
| Mod contents | Counts for multiplayer |
|---|---|
Any JSON under Definitions/ or
GalaxyConfig.json |
yes: id, version and files must match |
Only UI/ text, Visuals/ looks and files
under Resources/ (pictures, models, sounds) |
no: a looks-only mod, each player may use their own |
A looks-only mod still needs a restart when you switch it on or off. Multiplayer will not start while a restart is pending.
Joining a modded game: GET HOST MODS
- In the lobby browser, a lobby with a different mod set shows GET HOST MODS.
- The MODS page opens on the host's list and marks each mod: ready (installed at the exact same version), download, downloading, wrong version, or NOT ON THE WORKSHOP (a host's local mod that was never published).
- DOWNLOAD subscribes to the missing items.
- When every mod is ready, APPLY switches your game to exactly the host's set, in the host's order, and turns everything else off.
- Restart ORION and join again.
Versions match as exact strings, so a host on 1.2.0 and a player on 1.2.1 do not match. The host's list carries up to 64 mods.
Saves
A save records the content it was made with. It loads as long as the effective content is the same: reordering mods that do not touch each other, or adding a looks-only mod, keeps it loading. It refuses to load when a rule mod is missing or changed, or when two mods replace the same thing and the other one now wins.
So any update that changes a rule file (a number, a new tech, a removed definition) means saves made with the old version no longer load with the new one; only looks-only changes keep them loading. Keep that in mind when you update a popular mod:
- say in the change note and description when an update breaks saves;
- keep Keys, numeric ids and the mod id stable, so a campaign started on the new version keeps working through later looks-only updates;
- bundle rule changes into fewer, larger updates rather than many small ones.
Troubleshooting
The MODS page tells you what is wrong with each mod under its description; the log has the full list.
Mod states on the MODS page
| State | Meaning | What to do |
|---|---|---|
| AVAILABLE | Found and valid, not enabled | ENABLE it, then restart |
| ACTIVE | Enabled and loaded | none |
| INVALID | The manifest is wrong, or the game or mod API version does not match | read the red line under the description |
| DUPLICATE ID | Two mods use the same id |
remove one, or change the id of your unpublished copy |
| BLOCKED | A dependency is missing, disabled, the wrong version, or part of a loop | install or enable the dependency, check its version range |
| DOWNLOAD / UPDATING | A Workshop item Steam has not finished downloading | press DOWNLOAD, or wait |
| LOCAL COPY USED | You subscribe to your own item; your local folder is used | none |
Errors and warnings
- Errors stop a mod from loading: an unknown name or
Key in a reference field, a wrong code name, a Key used by two ids, a
numeric id missing where one is needed, an unknown field in a tuning
table, or a duplicate event
id. The message names the file and the field. - Warnings let it load and show in amber under the
mod (the first three; the rest are in the log): a field the game does
not know (usually a typo; it is ignored), a reference to an id nothing
defines, or a field that has no effect (an empire's
StartingPolicies, a station'sModifierTypes). - Interface text and looks files that cannot be read are skipped and listed under the mod; they never stop the game.
- Assets of an unknown type, empty, or over their size cap are skipped without a message. If a picture does not show, check its type and size first.
When a mod breaks the game
If the enabled mods fail to load, ORION switches every mod off for that session and starts the base game. The MODS page then reads MODS FAILED TO LOAD; THE BASE GAME IS RUNNING, with the reason, and each mod shows "Failed to load this session". Your choices are kept: disable the broken mod and restart.
Editor support
docs/modding/schemas/ has a JSON schema for every
definition kind, tuning table and ethic file. In VS Code, copy the
schemas folder into your mod folder and
vscode-settings.json to .vscode/settings.json
there: the editor then completes field names, code names and base-game
Keys, and underlines unknown fields. Do not add a "$schema"
line to your files; the game would report it as an unknown field.
Common mistakes
- The mod does nothing. It is not enabled, or you did not restart. New mods are never enabled on their own.
- A base file edit lost other changes. Same path replaces the whole file; copy the full base file and change only what you mean to.
- My new tech never appears. Check
Weight(0 means never dealt),TierandPrerequisites; a tier-3 tech waits until enough tier-2 techs are researched. - Two mods fight over a definition. The later one in load order wins the whole definition. Move yours below the other, or declare it as a dependency.
- A save stopped loading after an update. The rule content changed; see Multiplayer and saves.
Logs
- The game log lists every mod problem in full.
- Steam's own logs:
Steam/logs/Workshop_log.txt(downloads) andSteam/workshopbuilds/depot_build_<appid>.log(uploads).
Reference
What can be modded, and where
| Content | Folder under content/ |
Identified by |
|---|---|---|
| Technologies | Definitions/Techs/ |
TechId or Key |
| Ship hulls and units | Definitions/Units/ |
TypeId |
| Ship modules | Definitions/Modules/ |
TypeId or Key |
| Stations and buildings | Definitions/Buildings/ |
TypeId |
| Planet buildings | Definitions/PlanetBuildings/ |
BuildingIndex |
| Planet types | Definitions/PlanetTypes/ |
TypeId |
| Minefields | Definitions/Minefields/ |
Tier |
| Empires | Definitions/Factions/ |
FactionId or Key |
| Crisis factions | Definitions/Crisis/ |
FactionId |
| Crisis scenarios | Definitions/CrisisScenarios/ |
Scenario 1 to 8 (retune) or Key |
| National campaigns | Definitions/Campaigns/ |
Id or Key |
| Governor traits | Definitions/Traits/ |
TraitId or Key |
| Events and anomalies | Definitions/Events/ |
id (replace by path) |
| Diplomacy dialogue | Definitions/Diplomacy/ |
file |
| Governments, faiths, ruler traits, doctrines | Definitions/Politics/Governments/,
Faiths/, RulerTraits/,
Doctrines/ |
Id, Key or name |
| Policies (12), government forms (4) | Definitions/Politics/Policies/,
Forms/ |
Id: retune only |
| Ethics (10) | Definitions/Ethics/ |
Id or Name: retune only |
| AI personality | Definitions/AI/personality.json |
file |
| Ship and fleet names | Definitions/Names/ship_names.json |
file (replaces the base list) |
| Tuning tables | Definitions/Combat/, Research/,
Espionage/ and the others in Worked examples |
file, field by field |
| Galaxy generation | GalaxyConfig.json |
file |
| Hints, Command Guide, tutorial text | UI/Hints/, UI/Guide/,
UI/Onboarding/ |
element, node or lesson id |
| Weapon, beam and shield looks | Visuals/Weapons/ |
TechId, Key or name |
| Shipsets | Visuals/Shipsets/ |
Key (new) or Id 1 to 7, 9, 10
(retune) |
| Pictures, models, map icons, sounds | Resources/ |
path |
Asset types and size caps
Files under content/Resources/ use the same path as the
game's StreamingAssets/Resources/: the same path replaces
the base file, a new path adds one.
| Type | Cap per file | Typical use |
|---|---|---|
.png, .jpg, .jpeg |
8 MB | tech icons (Tech_Icons/...), empire emblems
(Empire_Icons/<FactionName>/emblem_outline_ui.png),
leader pictures |
.svg |
1 MB | map icons (MapIcons/*.svg), outliner icons |
.glb |
64 MB | ship, station and asteroid models, shipsets |
.ogg, .wav |
32 MB | indexed for later; the game has no sound yet |
Other types, empty files and files over their cap are skipped. There is no pixel limit on pictures, but players with a lower texture detail setting see them downscaled, so 1024 to 2048 pixels on the long side is plenty.
Versions this guide covers
| Item | Value |
|---|---|
| ORION | 0.3.0 |
| Mod API | 1.0.0 |
| Workshop version tag | ORION 0.3 |
Not moddable yet
New portrait parts (an empire's Species picks from the
built-in parts), sound, new ship classes, new resources, new agreement
kinds, new victory types and translations all need code.
Content guidelines
- Publish only your own work, or work you have permission to share.
- No hateful, sexual or illegal content, and nothing against the Steam Subscriber Agreement.
- Say in the description what the mod changes, and whether it breaks saves or other mods.
- Use version numbers honestly: raise
versionwhen content changes, and keepidthe same.