Skip to content

demo-ck3: Product Brief

Status: approved (W-017).

Target app: apps/demo-ck3. Refs: concept §8, ecs-relations spec.

1. Vision

Player rules the royal House of Godwin of the Kingdom of England in 1066 (a small, simplified subset of the real realm), using marriages, granted titles, alliances, and the opinions of vassals to keep the crown in the family for 60 years while the characters age, wed, inherit, and scheme. The demo is a what-if game, not a historical simulation.

2. Audience and purpose

  • Audience: developers learning ECS / flecs concepts on koota. The demo must still be a 15–20 minute dynasty-management session on its own.
  • Teaches: relations as the model of a social world. Symmetric pairs (MarriedTo, AlliedWith), transitive and exclusive vassalage (VassalOf, with a materialized closure for "the whole realm"), traversal (up to the nearest crown, cascade to process liege before vassal), a ChildOf title hierarchy with names and path lookup, relation data (an opinion number on a pair), pair cleanup when characters die, and a monthly system pipeline (ecs-schedule).

3. Core loop

  1. User sees the realm: the title tree, the vassal chain, the family tree, and each character's opinion of the player.
  2. Player picks an action for the ruler: arrange a marriage, grant a vacant title to a living adult (not the Crown holder), propose an alliance, or do nothing.
  3. Player advances time by one month (or lets it run at a chosen speed).
  4. The month resolves: characters age, are born, wed, and die; titles pass to heirs; opinions shift; unhappy vassals revolt.
  5. User reads what changed in the event log and in the opinions, and plans the next action.
  6. Repeat until House Godwin has held the crown for 60 years (win) or loses it (lose), then restart.

4. ECS showcase

flecs concept Shown by Package
Entities, components, tags Characters with Age, House, Traits; Dead / Ruler / Crown tags (CK3-F02, CK3-F04) koota
ChildOf hierarchy, names, path lookup Title tree Kingdom → Duchy → County; "England/Mercia/Cheshire" paths and lookup by path (CK3-F01) ecs-relations
Symmetric relation MarriedTo: one marriage appears on both spouses; widowing on death clears both sides (CK3-F03) ecs-relations
Symmetric relation (second use) AlliedWith between two rulers (CK3-F05) ecs-relations
Exclusive + transitive relation, closure VassalOf (one liege each); "who is in this ruler's realm" and "would this grant make a loop" (CK3-F04; any living adult except the Crown holder can be granted a title, so the refusal is reachable in play) ecs-relations
up traversal Nearest crown above any vassal along VassalOf (CK3-F04) ecs-relations
cascade traversal Monthly loyalty check and realm outline ordered liege before vassal (CK3-F06) ecs-relations
Relation data Opinion(target) with a value and reasons (CK3-F05) koota
Plain relations ParentOf family tree; dead characters stay in the tree (CK3-F02) koota
Cleanup A dead character's marriage and vassal pairs are removed with them; destroying a title destroys its sub-titles (ChildOf autoDestroy, CK3-F11) koota, ecs-relations
Pipeline phases, ordered systems Monthly pipeline: age → birth/death → succession → opinions → loyalty → end checks (CK3-F02, CK3-F06) ecs-schedule
Observers Event log entries on marriage, death, grant, and revolt (CK3-F06) koota
Serialization Save and resume a dynasty (CK3-F07) ecs-serialize
Explorer-style inspection Live entity/trait/relation panel (CK3-F09) ecs-devtools

5. Backlog

ID Feature Milestone Work
CK3-F01 User sees the Kingdom of England (1066, simplified) as a title tree (Kingdom, 2 Duchies, 6 Counties) with the holder of each title, can select a title or character to see its full path (e.g. England/Mercia/Cheshire), and can find a title by typing its path M1 W-072, W-083
CK3-F02 User sees about 20 characters of 4 houses with name, age, and house, and can open a family tree (parents, siblings, children) for any character; player can pause, step by one month, and change the speed; characters age and die, and a dead ruler's titles pass to the eldest living child (else they return to the liege) M1 W-072, W-084, W-085, W-086, W-087, W-088
CK3-F03 Player can arrange a marriage between two eligible unmarried adults and sees it on both spouses at once; married couples have children over the months; a spouse's death makes the other a widow M1 W-072, W-089, W-090, W-091
CK3-F04 Player can grant a vacant county or duchy to any living adult except the Crown holder (landless or not) to make them a vassal of the title's liege; user sees every character's liege chain, the nearest crown above them, and the whole realm below any ruler; the game refuses a grant that would make a liege the vassal of their own vassal M1 W-072, W-092, W-093, W-094, W-095
CK3-F05 User sees each character's opinion of the player with reasons (same house, married into the family, granted a title, passed over for a title); player can propose an alliance to another ruler, who accepts if their opinion is high enough, and the alliance shows on both rulers M1 W-072, W-096, W-097, W-098
CK3-F06 Each month vassals are checked from the top of the realm down: a vassal whose opinion of their liege stays low for 3 months revolts and breaks away with their own vassals; user sees an event log and a realm outline, and wins after 60 years on the crown, or loses if the crown is lost or the house dies out, and can restart M1 W-072, W-099, W-100, W-101, W-102, W-103
CK3-F07 Player can save a dynasty and resume it after reload M2
CK3-F08 Player can control the whole game from the keyboard with on-screen key hints M2
CK3-F09 User can open a devtools panel listing entities, traits, and relation pairs (MarriedTo, VassalOf, ChildOf) live M2
CK3-F10 Player can pick the scenario (realm, start year, goal) from a list in content data M2
CK3-F11 Player can destroy a duchy title and sees its counties' titles destroyed with it and their holders lose the land M2
CK3-F12 Player can see an opinion history for each pair and a timeline of the dynasty's major events M2
CK3-F13 Player can press a claim and fight a war over a title, with allies called in later
CK3-F14 Characters have personality traits, stress, schemes, and secrets later
CK3-F15 User sees a map with counties, and rulers have armies and gold later

M1 order: CK3-F01, CK3-F02, CK3-F03, CK3-F04, CK3-F05, CK3-F06.

Dependencies on ecs-relations

Feature Needs Why
CK3-F01 REL-F06 (ChildOf), REL-F07 (Name, getPath, lookup) Title tree, paths, and lookup
CK3-F02 – (plain koota ParentOf) Family tree must not use ChildOf: its autoDestroy would destroy children when a parent dies
CK3-F03 REL-F01 (symmetric) MarriedTo
CK3-F04 REL-F02 (isReachable), REL-F03 (transitive closure), REL-F04 (up) Loop check on grants, realm query, nearest crown
CK3-F05 REL-F01 (symmetric, second relation AlliedWith) Alliances. Opinion is plain koota relation data
CK3-F06 REL-F05 (cascade) Liege-before-vassal processing and outline
M2 CK3-F11 REL-F06 (autoDestroy cleanup) Sub-title destruction
(all) REL-F08 (package rules) README and preconditions; the last package item

Chosen relation order and why

Order: hierarchy (REL-F06, F07) → symmetric (REL-F01) → transitive and up (REL-F02, F03, F04) → cascade (REL-F05). This answers ecs-relations open question 9 for demo-ck3: the first ck3 feature needs area C, not area A.

  • Hierarchy first. It has no dependency on another group, needs no hooks, and is the lowest risk. Titles and names give every later view something to show, and a title tree is valuable on its own (CK3-F01).
  • Symmetric next. It is the smallest hook-based feature (S), and a marriage is a visible, player-driven action that gives the family tree its growth (CK3-F03). It is reused for alliances in CK3-F05, which proves the install is per relation.
  • Transitive and up after that. They are the riskiest and largest package area (REL-F03 is M, with its hook recompute). They need characters, titles, and grants in place so the realm and the nearest crown can be seen, not just tested (CK3-F04). REL-F02 comes before REL-F03 because the closure needs isReachable.
  • cascade last. Depth order is only meaningful once a vassal tree exists, and it serves the monthly loop that closes the game (CK3-F06). Decided (ecs-relations open question 3): cascade yields level order, all rulers at depth 0 first, then their vassals. No longer an open question.
  • Suggested package work-item order for Triage: F06, F07, F01, F02, F03, F04, F05, F08. This differs from the spec default (F01 to F08) only in putting area C first. F03 still follows F02, and F07 follows F06.

Notes: - Every M1 action (select, marry, grant, propose, advance time) must already be keyboard-reachable (demo rule); CK3-F08 adds hints and polish. - Dependency/risk (all M1): the demo cannot start CK3-F01 before the matching ecs-relations group exists. A demo never implements engine features; a missing capability stops the feature and needs a package item. - Dependency/risk (timing): ecs-schedule v0 has no intervals or fixed step. The month clock is a world singleton advanced by the demo from dt and the chosen speed; the month pipeline is a manual phase chain stepped once per month. - Dependency/risk (ChildOf): koota cannot prevent cycles or duplicate names (spec KL3). Title content is fixed in src/content/, so M1 has no cycle risk; vassal cycles are prevented in the grant action by isReachable (CK3-F04). Names used in paths must not contain /. - Dependency/risk (restart): hooks are lost on world.reset() (spec KL4). Restart creates a fresh world and installs symmetric and transitive again. - Dependency/risk (CK3-F07, CK3-F09): need the ecs-serialize and ecs-devtools implementations. Both are M2 so M1 depends only on koota, ecs-schedule, and ecs-relations. - Sizing (Triage): CK3-F04 touches three package groups in the demo and is the largest M1 feature. Decided guidance for Triage: if CK3-F04 is rated above M, up (REL-F04, nearest crown) splits into its own item after the rest of CK3-F04.

6. Non-functional targets

  • Performance: up to 60 character entities (including dead ones) and 12 titles; UI stays at 60 FPS at the fastest speed; one month resolves in under one frame of logic.
  • Accessibility: all actions keyboard-reachable; WCAG AA contrast; opinions, marriage, and vassalage shown as text and numbers, not color alone; the title tree, family tree, and realm outline are readable as nested lists.
  • Persistence: M1 none. M2 saves the full dynasty (characters, titles, ChildOf, MarriedTo, AlliedWith, VassalOf, Opinion data, clock, event log) via ecs-serialize. The closure relation is rebuilt on load.

7. Path to a real app

  • Characters, houses, titles, realm layout, start year, and goal live in src/content/ and can be swapped for other scenarios or generated data.
  • RNG (births, deaths, opinion events) behind one seam, so a dynasty can be seeded and replayed.
  • Monthly pipeline as ecs-schedule phases, so new phases (schemes, wars, economy) slot in without rewriting systems.
  • Decision functions for acceptance (marriage, alliance, vassal loyalty) in one place each, replaceable by richer rules.
  • AI rulers behind one decision function (M1: no AI actions beyond revolts), so AI diplomacy can be added.
  • World state serializable, leaving room for multiplayer or hot-seat play.

8. Out of scope

  • A map, armies, gold, and wars in M1 (see CK3-F13, CK3-F15).
  • Claims, succession laws other than "eldest living child", and elective or partition rules.
  • Culture, religion, personality traits, stress, schemes, and secrets (see CK3-F14).
  • Pregnancy detail, bastards, divorce, and concubines; marriage is one man or woman with one spouse.
  • Opinion modifiers other than those named in CK3-F05.
  • Deeper realm tiers than Kingdom, Duchy, and County; no Empire in M1.
  • More than one playable house; the player always rules House Godwin.
  • Invasions and other historical event scripts (no Norman or Norse invasion); the demo is not a historical simulation.
  • Multiplayer and networking.
  • 3D rendering (R3F); plain 2D UI only.

9. Starting content (illustrative, lives in src/content/)

Setting: England in 1066, reduced to a playable subset. Real people and places are used as a plausible basis. All ages, family ties, holdings, and the county split are approximations chosen for play, not verified facts, and the data may be adjusted. Period titles (earl, ealdorman) are shown with the tier names Duchy and County.

  • Realm: Kingdom of England, Duchy of East Anglia (counties Norfolk, Suffolk, Essex), Duchy of Mercia (counties Cheshire, Warwickshire, Leicestershire). The shires stand in for counties (approximate); some start vacant so there is land to grant.
  • Houses: Godwin (royal, the player's), Leofric (Mercia), Wessex (the old royal line), Dunkeld (Scotland). King Malcolm III of Scotland (Dunkeld) is the first alliance candidate. No Normans in the roster.
  • Start: year 1066. King Harold Godwinson (about 44) and Queen Ealdgyth (about 20); their heir Godwin and his brothers Edmund and Magnus (teenagers, approximate); Harold's brothers Gyrth (Duke of East Anglia) and Leofwine; Queen Edith (the widow, about 40) and the dowager Gytha; Edwin (Duke of Mercia) and his brother Morcar (landless in the demo), both of House Leofric; Edgar Ætheling (about 14) and his sister Margaret (about 21, unmarried) of House Wessex; King Malcolm III of Scotland. About 6 more invented landless thegns and daughters fill the roster to about 20 characters, to marry or reward. Any living adult except the king can be granted land, including a duke such as Edwin, which lets the player trigger the loop refusal. Goal year: 1126.