Pulled from Notion project docs: overview, architecture, data model, event system, line logic, and implementation notes for the family-tree generator + TTS narrator. Co-Authored-By: Claude <noreply@anthropic.com>
4.4 KiB
4.4 KiB
Data Model
All identifiers and code are in English.
Enums
class Gender(IntEnum):
MALE = 0
FEMALE = 1
NONBINARY = 2
class PartnerType(IntEnum):
MARRIAGE = 0
AFFAIR = 1
POLITICAL = 2
ILLEGITIMATE = 3
class StageType(IntEnum):
CHILD = 0
TEEN = 1
YOUNG_ADULT = 2
ADULT = 3
SENIOR = 4
class Event(IntEnum):
# Category 1 — Death
DEATH_ILLNESS = 10
DEATH_ACCIDENT = 11
DEATH_COMBAT = 12
DEATH_OLD_AGE = 13
DEATH_CHILDBIRTH = 14 # mother dies during birth
# Category 2 — Partnership
PARTNER_MARRIAGE = 20
PARTNER_AFFAIR = 21
PARTNER_ENGAGEMENT = 22
PARTNER_POLITICAL = 23
PARTNER_CHILDHOOD_PROMISE = 24
# Category 3 — Offspring
CHILD_BORN = 30
CHILD_TWINS = 31
CHILD_TRIPLETS = 32
CHILD_STILLBORN = 33
CHILD_ADOPT = 34 # only path to offspring for NONBINARY; from YOUNG_ADULT onwards
# Category 4 — Daily Life
DAILY_FRIENDSHIP = 40
DAILY_FAMILY = 41
DAILY_TEMP_CHAR = 42
# Category 5 — Travel
TRAVEL_NEAR = 50
TRAVEL_FAR = 51
TRAVEL_PILGRIMAGE = 52
# Category 6 — Learning
LEARN_APPRENTICESHIP = 60
LEARN_MENTOR = 61
LEARN_SELF = 62
# Category 7 — Conflict (personal)
CONFLICT_PERSONAL = 70
CONFLICT_FIGHT = 71
CONFLICT_FEUD = 72
# Category 8 — Discovery
DISCOVER_OBJECT = 80
DISCOVER_SPELL = 81
DISCOVER_WONDER = 82
DISCOVER_KNOWLEDGE = 83
# Category 9 — Local Conflict
LOCAL_REBELLION = 90
LOCAL_PLAGUE = 91
LOCAL_DISASTER = 92
LOCAL_CRISIS = 93
# Category 10 — Intrigue
INTRIGUE_POLITICAL = 100
INTRIGUE_EXILE = 101
INTRIGUE_CONSPIRACY = 102
# Category 11 — Illness / Injury
ILLNESS_WEAK = 110
ILLNESS_SEVERE = 111
ILLNESS_CHRONIC = 112
INJURY_ACCIDENT = 113
INJURY_COMBAT = 114
event_type // 10 → category, event_type % 10 → subtype within category.
Person
Person {
id: str
name: str
gender: Gender
birth_year: int # absolute, set when person is created via parent event
death_year: int | None # birth_year + age_at_death
alive: bool
appearance: dict
profession: str | None # set by a LEARN event
home: str
is_ancestor: bool # True only for Person 1
parent_id: str | None # previous active node; None = joined from outside
generation: int
partners: PartnerEntry[]
events: str[] # event IDs in chronological order
acquaintances: str[] # IDs from person_pool only (not family tree)
stages: Stage[]
}
PartnerEntry {
person_id: str
type: PartnerType
children_ids: str[] # all children from this union
}
Stage
Stage {
type: StageType
age: { from: int, to: int } # relative to person
events: str[] # event IDs
}
Stage Age Ranges
| Stage | Age |
|---|---|
| Child | 0–12 |
| Teen | 12–16 |
| Young Adult | 16–32 |
| Adult | 32–50 |
| Senior | 50–X (LLM decides) |
EventEntry
EventEntry {
id: str
type: Event # e.g. Event.ILLNESS_SEVERE
age: int # age of person at time of event
# absolute_year: @property -> person.birth_year + self.age
location: str | None # None = takes place at person.home
location_is_temp: bool # True = travel destination, False = known location
participants: str[] # person_ids or pool_ids
result: dict # predetermined simulation outcome
context: dict # extra info passed to LLM prompt
follow_bonus: Event[] # event types made more likely after this event
# e.g. after TRAVEL_FAR -> [DISCOVER_OBJECT, DISCOVER_WONDER]
}
FamilyTree & person_pool
FamilyTree {
persons: dict[str, Person] # all family tree persons
person_pool: dict[str, Person] # temporary chars with no tree membership
# e.g. random villager
# distant cousin -> lives in persons, not here
world: World
current_generation: int
active_node: str # person_id of currently narrated person
}
World {
start_year: int # randomly generated, max 4 digits, no calendar system stated
name: str
epoch_flavor: str # setting keywords passed to LLM
}