Files
lords-of-ash/docs/ck3-modding/ck3-modding-reference.md
T

18 KiB

CK3 Modding Reference

Practical reference for developing Crusader Kings III mods, with emphasis on total conversion considerations. Based on official wiki documentation, community guides, and patterns from major TC mods (AGOT, Elder Kings 2, Princes of Darkness, Atlantis template).

Mod Structure

Directory Layout

my_mod/                              # Mod root folder
├── descriptor.mod                   # Inner descriptor (no path field)
├── thumbnail.png                    # Steam Workshop thumbnail
├── common/                          # Game data definitions (80+ subdirs)
│   ├── bookmarks/                   # Start screen scenarios
│   ├── buildings/                   # Holdings and buildings
│   ├── casus_belli_types/           # War justifications
│   ├── character_interactions/      # Diplomatic actions
│   ├── council_positions/           # Council roles
│   ├── council_tasks/               # Council job actions
│   ├── culture/                     # Culture definitions
│   │   ├── cultures/                # Culture entries
│   │   ├── pillars/                 # Heritage, language, martial custom, etc.
│   │   └── traditions/              # Cultural traditions
│   ├── decisions/                   # Player/AI decisions
│   ├── defines/                     # Game constants and tunables
│   ├── dynasties/                   # Dynasty definitions
│   ├── dynasty_houses/              # Cadet branches
│   ├── dynasty_legacies/            # Legacy tracks
│   ├── ethnicities/                 # Portrait ethnicity definitions
│   ├── factions/                    # Faction types
│   ├── governments/                 # Government forms
│   ├── holdings/                    # Holding types
│   ├── landed_titles/               # Title hierarchy (empire → barony)
│   ├── laws/                        # Realm laws
│   ├── lifestyles/                  # Lifestyle focuses and perks
│   ├── men_at_arms_types/           # Custom troop types
│   ├── modifiers/                   # Static modifiers
│   ├── nicknames/                   # Character nicknames
│   ├── on_action/                   # Event hooks (game triggers)
│   ├── province_terrain/            # Terrain types per province
│   ├── religion/                    # Religion definitions
│   │   ├── religions/               # Religion and faith entries
│   │   └── holy_sites/              # Holy site definitions
│   ├── schemes/                     # Intrigue schemes
│   ├── script_values/               # Reusable numeric values
│   ├── scripted_effects/            # Reusable effect blocks
│   ├── scripted_modifiers/          # Reusable modifier blocks
│   ├── scripted_triggers/           # Reusable condition blocks
│   └── traits/                      # Character traits
├── events/                          # Event scripts
├── gfx/                             # Graphics (icons, portraits, UI art)
│   └── interface/icons/traits/      # Trait icon DDS files
├── gui/                             # UI layout overrides
├── history/                         # Starting game state
│   ├── characters/                  # Character definitions with dates
│   ├── provinces/                   # Province culture/religion/holdings
│   └── titles/                      # Title holder history
├── localization/                    # Display strings
│   └── english/                     # l_english.yml files
│       └── replace/                 # Overrides for vanilla loc keys
└── map_data/                        # Map files (TC only)
    ├── default.map                  # Province groupings
    ├── definitions.csv              # Province ID → RGB mapping
    ├── geographical_regions/        # Regional groupings
    ├── provinces.png                # Province map image
    ├── rivers.png                   # River overlay
    └── heightmap files              # Terrain elevation
my_mod.mod                           # Outer descriptor (has path field)

The .mod Descriptor Files

Every mod needs two descriptor files with identical content except for the path field:

Outer file (my_mod.mod) — sits alongside the mod folder in the mod directory. Includes the path field:

version="1.0.0"
tags={
    "Total Conversion"
}
name="My Mod"
supported_version="1.12.*"
path="mod/my_mod"

Inner file (my_mod/descriptor.mod) — sits inside the mod folder. Same content but without the path field:

version="1.0.0"
tags={
    "Total Conversion"
}
name="My Mod"
supported_version="1.12.*"

Descriptor Fields

Field Required Description
name Yes Display name in the launcher
version No Mod version string (informational only)
supported_version Yes Game version compatibility (wildcards OK: 1.12.*)
path Outer only Path to mod folder. Use forward slashes only.
tags No Category tags ("Total Conversion", "Gameplay", etc.)
picture No Thumbnail filename (e.g., thumbnail.png)
remote_file_id No Steam Workshop item ID (added automatically on upload)

Mod Installation Paths

Platform Path
Windows %USERPROFILE%\Documents\Paradox Interactive\Crusader Kings III\mod\
Linux ~/.local/share/Paradox Interactive/Crusader Kings III/mod/
Mac ~/Library/Application Support/Paradox Interactive/Crusader Kings III/mod/

Both the .mod file and the mod folder live in this directory.

File Loading and Override Rules

How CK3 Loads Mod Files

When a mod provides a file at the same path as a vanilla file, the mod's file replaces the entire vanilla file. This is whole-file replacement — you cannot partially override a file just by having the same filename.

LIOS — Last In, Only Served (Most Files)

For most game data (traits, decisions, events, etc.), when multiple definitions of the same object exist across different files, the last loaded definition wins. Files load in ASCIIbetical order by filename:

  • 01_my_traits.txt loads after and overrides objects in 00_vanilla_traits.txt
  • Within the same file, later definitions override earlier ones

This means you can override a single vanilla object by creating a new file that sorts after the vanilla file and redefining just that object.

FIOS — First In, Only Served (GUI Files)

GUI types and templates use the opposite rule: the first loaded definition wins. To override vanilla GUI, name your file to sort before the vanilla file.

Localization Override

Place overriding localization files in localization/<language>/replace/. Files in the replace/ subfolder can override individual keys from vanilla without errors. Overriding keys outside of replace/ works but produces log warnings.

Multiple Mods

When two mods provide the same file, the mod lower in the playset (load order) takes priority.

Localization

File Format

Localization files are YAML with strict requirements:

  • Encoding: UTF-8 with BOM (byte order mark). Files without BOM will silently fail to load or cause validation errors.
  • Filename: Must end in _l_<language>.yml (e.g., mistborn_traits_l_english.yml)
  • First line: Must declare the language: l_english:

Entry Format

l_english:
 key_name:0 "Display text with $VARIABLE$ substitution"
 another_key:1 "Text with [concept|E] references"

The number after the colon (:0, :1) is a version number used by Paradox for tracking translation updates. For mods, use 0 or 1.

Tips

  • Copy an existing vanilla .yml file to inherit the correct BOM encoding
  • Every trait, event option, decision, title, modifier, and event description needs a localization entry
  • Missing keys display as raw key names in-game (e.g., trait_misting_coinshot)

Events

Namespace Declaration

Every event file must declare its namespace at the top:

namespace = mistborn_snapping

Event Structure

mistborn_snapping.0001 = {
    type = character_event
    title = mistborn_snapping.0001.t
    desc = mistborn_snapping.0001.desc
    theme = intrigue

    trigger = {
        # Conditions that must be true
    }

    immediate = {
        # Effects that run before the event displays
    }

    option = {
        name = mistborn_snapping.0001.a
        # Effects when this option is chosen
    }
}

Event Types

  • character_event — Targets a character, shows a popup
  • letter_event — Displayed as a letter/message
  • court_event — Royal court events (DLC)

Traits

Structure

trait_name = {
    index = 200                          # Unique index, avoid vanilla range

    category = fame                      # fame, lifestyle, personality, etc.

    genetic = yes                        # Can be inherited
    inherit_chance = 15                  # Base inheritance chance (%)
    both_parent_has_trait_inherit_chance = 30

    # Stat modifiers
    prowess = 3
    martial = 1

    # Display
    icon = "gfx/interface/icons/traits/trait_name.dds"
    ruler_designer_cost = 50
    shown_in_ruler_designer = yes
}
  • Use index values 200+ to avoid conflicts with vanilla traits
  • group field makes traits mutually exclusive within that group
  • birth = <weight> controls random assignment at birth (0 = never)

Scripted Triggers and Effects

Triggers

Reusable conditions that return true/false:

is_allomancer_trigger = {
    OR = {
        has_trait = trait_misting_coinshot
        has_trait = trait_misting_lurcher
        has_trait = trait_mistborn
    }
}

Effects

Reusable blocks of game actions:

activate_allomancy_effect = {
    remove_trait = trait_allomantic_potential
    random_list = {
        30 = { add_trait = trait_misting_coinshot }
        30 = { add_trait = trait_misting_lurcher }
        5  = { add_trait = trait_mistborn }
    }
}

On-Actions

Game hooks that fire events/effects when specific things happen:

on_birthday = {
    events = {
        mistborn_snapping.0001    # Check for natural snapping
    }
    effect = {
        # Inline effects
    }
}

Common hooks: on_birthday, on_yearly_pulse, on_game_start, on_death, on_war_started, on_title_gain, on_marriage.

Decisions

my_decision = {
    picture = "gfx/interface/illustrations/decisions/decision_something.dds"

    is_shown = {
        # Conditions for the decision to appear in the list
    }

    is_valid = {
        # Conditions for the decision to be clickable
    }

    cost = {
        gold = 100
        prestige = 200
    }

    effect = {
        # What happens when the player takes the decision
    }

    ai_will_do = {
        base = 10   # AI weight for taking this decision
    }
}

History Files

Characters

900001 = {
    name = "Devinshae"
    dynasty = dynasty_venture
    religion = "steel_ministry"
    culture = "noble_scadrian"
    trait = trait_misting_seeker
    trait = education_intrigue_4
    father = 900000
    900.1.1 = { birth = yes }
    930.1.1 = { death = yes }
}

Dates use yyyy.mm.dd format. Use birth = yes and death = yes inside date blocks. Character IDs should avoid vanilla ranges (use 900000+).

Titles

e_final_empire = {
    900.1.1 = {
        holder = 900001
    }
}

Total Conversion Considerations

The Core Challenge

A total conversion must clear vanilla CK3 content while building an entirely new world. This means replacing or masking: the map, all provinces and titles, all cultures and religions, all characters and dynasties, all bookmarks.

Approaches to Vanilla Content

Option A: Replace with empty files — Create empty files matching every vanilla filename you want to suppress. Simple but tedious and fragile across game updates.

Option B: Preserve but hide (Atlantis approach) — Keep vanilla content as invisible placeholders, redirect references to dummy entries, hide elements through GUI overrides. More resilient to game patches.

Option C: replace_path directive — The replace_path field in descriptor.mod should tell the engine to ignore entire vanilla directories. In practice this has been unreliable in CK3 (reported broken since 1.1). Don't depend on it; use Option A or B instead.

Map

Total conversions that want a custom map must provide:

  • map_data/provinces.png — Province boundaries (each province a unique RGB)
  • map_data/definitions.csv — Maps province IDs to RGB colors
  • map_data/rivers.png — River overlay
  • map_data/default.map — Province groupings and sea zones
  • map_data/heightmap files — Terrain elevation
  • map_data/geographical_regions/ — Regional groupings

Broken rivers.png files can crash the game. Test map changes incrementally.

If your TC doesn't need a custom map (e.g., uses abstract/minimal geography), you can reuse the vanilla map and just reassign provinces.

Portraits and DNA

  • Custom portrait assets go in gfx/portraits/
  • Ethnicities are defined in common/ethnicities/
  • Characters without proper ethnicity/portrait setup will appear bald
  • Add has_scripted_appearance = yes to character history to use scripted (non-DNA) appearance
  • DNA strings can be generated using the in-game portrait editor (debug mode)

Culture and Religion Families

  • Religion families (family = rf_scadrial) are auto-created on first use but verify this works with your CK3 version
  • Culture pillars (heritage, language, martial_custom, ethos) must be defined before cultures that reference them
  • File load order matters — name pillar files to sort before culture files

Bookmarks

Bookmarks define the start screen scenarios. Each needs:

  • A bookmark definition in common/bookmarks/
  • Character entries with portraits and descriptions
  • Localization for all display text
  • At least one playable character with a valid title

What Bleeds Through

Even in a TC, vanilla content can appear unexpectedly:

  • Decisions — Vanilla decisions may show up if not replaced/emptied
  • Events — Vanilla on_action hooks still fire unless overridden
  • GUI text — Hardcoded strings and tooltips reference vanilla concepts
  • AI behavior — AI weights reference vanilla traits, cultures, religions
  • Name lists — Without custom name lists, characters get vanilla names

Test thoroughly and check error.log for references to content you didn't create.


Development Workflow

Setup

  1. Create your mod folder in the CK3 mod directory
  2. Create both .mod files (outer with path, inner without)
  3. Add Steam launch options: -debug_mode -develop
  4. Create a playset in the launcher with your mod enabled
  5. Reload mods in launcher: Mods → Manage All Mods → Reload Installed Mods

Debug Mode

Launch with -debug_mode to enable:

  • Console — Press tilde (~) to open. Tab for command list.
  • error.log — Written to Documents/Paradox Interactive/Crusader Kings III/logs/error.log. Check this after every launch.
  • Event testingtest_event <id> <char_id> checks if an event can fire; debug_event <id> <char_id> forces it to fire

Useful Console Commands

Command Description
event <id> Fire an event for the player character
test_event <id> <char_id> Check if event can trigger (prints result)
debug_event <id> <char_id> Force-fire event and print trigger info
add_trait <trait> Add a trait to the player character
remove_trait <trait> Remove a trait
add_gold <amount> Add gold
add_prestige <amount> Add prestige
yesmen AI always accepts proposals
observe Enter observer mode
charinfo Toggle character debug info
reload <file> Hot-reload a specific file

Iterative Testing

  1. Make changes to mod files
  2. Launch game (or use reload for supported file types)
  3. Check error.log for new errors
  4. Use console to test specific events/traits/decisions
  5. Fix issues, repeat

Publishing to Steam Workshop

  1. In the CK3 launcher, go to Mods
  2. Click "Upload Mod" → select your mod
  3. Set the suggested game version, add thumbnail and description
  4. The launcher handles packaging and upload
  5. remote_file_id is added to your .mod file automatically

To update: make changes locally, then re-upload through the launcher.


Common Pitfalls

Issue Cause Fix
Localization not loading Missing UTF-8 BOM encoding Re-save files as UTF-8 with BOM
Traits not appearing Wrong index collision or missing loc Use unique indices 200+, add loc entries
Events silently failing Namespace mismatch or missing event file Check namespace declaration matches event prefix
Decision not showing is_shown trigger failing Test individual trigger conditions in console
Vanilla content showing Not all vanilla files overridden Empty/replace all relevant vanilla files
Characters appear bald Missing ethnicity or portrait data Add has_scripted_appearance or define ethnicities
Game crash on load Broken map files or circular references Test incrementally, check error.log
replace_path not working Known CK3 bug/limitation Use empty file replacement instead
Wrong trait activating LIOS override — file sort order wrong Name files to sort correctly (00_, 01_ prefix)
Mod not detected .mod file path wrong or uses backslashes Use forward slashes only in path field

Resources