The step-by-step recipes for adding to the game without fighting the architecture. The classes referenced here are described in class-hierarchy.md; the config they read is in config-formats.md.
Ship, LandingSite, or Person - or, for a new
character, prefer a new Routine (see below) over a new classupdate() and/or draw()SpaceScreen (or a location’s NPC list)get_state()/restore_state() if saveablehandle_input(), draw() (and update() if it needs one)current_screen string and branches in main.py’s loop: input in
phase 1, drawing in phase 3, and — only if the screen has a live
simulation — a case in step_world() for phase 2 (the fixed-timestep
accumulator). A modal that freezes the world needs no step_world() case.
See UI_FLOW.md.handle_input() return valuesRoutine class (own file, one class per file) with
__init__(self, route), start(self, character), run(self, character)
character.ship-delegated methods (engage_seek, etc.)
for ship-flying behavior, or character.person.x/y directly for local
(no-ship) behavior - never both in the same routineROUTINE_REGISTRY (game/world/character.py) under a
short config name, and/or wire a role default into ROLE_ROUTINES"role": "<name>" (role default) or
"routine": "<registry name>" (explicit, wins over the role) on the
relevant pilots.json entry (ship-flying) or the location config’s
npcs[] entry (local) - no other code changes neededSee config-formats.md — it
is almost always a ship_types.json + graphics.json entry, no Python.