core package

Subpackages

Submodules

core.animation module

class core.animation.AnimationClip(name: str)[source]

Bases: object

static from_data(name: str, data: dict) AnimationClip[source]
load_frames()[source]
to_data() dict[source]
class core.animation.AnimationController[source]

Bases: object

ROOT_NODE_NAME = 'Root'
add_node(name: str, clip_path: str, position: tuple = (0, 0))[source]
add_transition(from_node: str, to_node: str, conditions: list = None, trigger: str = '', on_finish: bool = False)[source]
static from_data(data: dict) AnimationController[source]
get_default_state()[source]
remove_node(name: str)[source]
rename_node(old_name: str, new_name: str)[source]
to_data() dict[source]
class core.animation.AnimationNode(name: str, clip_path: str = '', position: tuple = (0, 0))[source]

Bases: object

class core.animation.AnimationTransition(from_node: str, to_node: str, conditions: list = None, trigger: str = '', on_finish: bool = False)[source]

Bases: object

core.coroutine_manager module

Lightweight coroutine scheduler for user scripts.

User scripts yield special instruction objects to pause execution:

class MyScript:
    def on_start(self):
        self.start_coroutine(self.spawn_loop())

    def spawn_loop(self):
        while True:
            self.logger.info("spawning")
            yield Wait(0.5)          # wait 0.5 seconds
            yield WaitFrames(2)      # wait 2 frames

The ScriptSystem ticks the coroutine manager each frame via CoroutineManager.tick(dt).

class core.coroutine_manager.CoroutineManager[source]

Bases: object

Manages a set of running coroutines. Typically one per entity.

property count: int
start(gen: Generator)[source]

Schedule a new coroutine (a generator).

stop_all()[source]

Cancel every running coroutine.

tick(dt: float)[source]

Advance all coroutines by dt seconds. Call once per frame.

class core.coroutine_manager.Wait(seconds: float)[source]

Bases: object

Pause coroutine for seconds seconds.

seconds
class core.coroutine_manager.WaitFrames(frames: int = 1)[source]

Bases: object

Pause coroutine for frames render frames.

frames

core.debug_overlay module

On-screen debug overlay for runtime diagnostics.

Toggle with DebugOverlay.enabled = True or bind to a key in a script.

Displays: - FPS (smoothed) - Entity count - Per-system update timings (if profiling is enabled on the World)

Usage:

from core.debug_overlay import DebugOverlay

# In player or script setup:
DebugOverlay.enabled = True        # show overlay
DebugOverlay.show_fps = True
DebugOverlay.show_entity_count = True
DebugOverlay.show_system_timings = True
class core.debug_overlay.DebugOverlay[source]

Bases: object

Static debug overlay drawn on top of the game surface.

bg_color: tuple = (0, 0, 0, 160)
color: tuple = (0, 255, 0)
classmethod draw(surface: Surface)[source]

Draw the overlay onto surface. Call after all game rendering.

enabled: bool = False
font_size: int = 14
position: tuple = (8, 8)
classmethod reset()[source]

Reset all collected stats.

show_entity_count: bool = True
show_fps: bool = True
show_system_timings: bool = True
classmethod update(dt: float, world=None)[source]

Call once per frame to collect stats.

core.ecs module

class core.ecs.Component[source]

Bases: object

Base class for all components

on_destroy()[source]
class core.ecs.Entity(name: str = 'GameObject')[source]

Bases: object

add_child(child: Entity)[source]
add_component(component: Component)[source]
add_group(group: str)[source]
add_tag(tag: str)[source]

Add a lightweight tag (no world indexing).

destroy() bool[source]
property events: EventSystem
get_child(name: str) Entity[source]

Returns the first child with the given name.

get_children() list[source]

Returns the children list of this entity.

get_children_copy() list[source]

Returns a copy of the children list.

get_component(component_type: Type[Component]) Any[source]
get_components(component_type: Type[Component]) List[Any][source]

Returns a list of all components matching component_type (including subclasses).

get_component() only returns the exact-type entry. This method walks every attached component and collects those that are instances of component_type, which is useful when an entity may carry several components that share a common base class (e.g. multiple colliders).

has_group(group: str) bool[source]
has_tag(tag: str) bool[source]

Check if the entity has a tag.

hide()[source]
is_physics_processing() bool[source]
is_visible() bool[source]
process_physics(enabled: bool)[source]
remove_child(child: Entity)[source]
remove_component(component_type: Type[Component])[source]
remove_group(group: str)[source]
remove_tag(tag: str)[source]

Remove a tag if present.

set_layer(layer: str)[source]
show()[source]
class core.ecs.EntityQuery(world: World)[source]

Bases: object

Fluent query builder for filtering entities in a World.

all() list[source]

Return all matching entities.

count() int[source]

Return the number of matching entities.

first()[source]

Return the first matching entity, or None.

in_group(group: str) EntityQuery[source]

Filter to entities belonging to group.

physics_enabled() EntityQuery[source]

Filter to entities with physics processing enabled.

visible() EntityQuery[source]

Filter to visible entities only.

with_component(*component_types) EntityQuery[source]

Filter to entities that have all listed component types.

with_tag(tag: str) EntityQuery[source]

Filter to entities that have tag.

class core.ecs.System[source]

Bases: object

Base class for all systems

on_added_to_world()[source]

Called after the system is added to a World and self.world is set.

on_removed_from_world()[source]

Called just before the system is removed from a World.

required_components: tuple[type, ...] = ()
update(dt: float, entities: List[Entity])[source]
class core.ecs.World[source]

Bases: object

Manages all entities and systems in a scene

add_system(system: System)[source]
create_entity(name: str = 'GameObject') Entity[source]
destroy_entity(entity: Entity)[source]
disable_profiling()[source]

Stop recording per-system execution times.

enable_profiling()[source]

Start recording per-system execution times each tick.

entities: List[Entity]
get_entities_by_name(name: str) List[Entity][source]

Returns all entities with the given name.

get_entities_in_group(group: str) List[Entity][source]
get_entities_with(*component_types: Type[Component]) List[Entity][source]

Returns a list of entities that have all the specified components. Uses cached sets for O(1) lookups per component type.

get_entity_by_id(entity_id: str) Entity[source]
get_entity_by_name(name: str) Entity[source]

Returns the first entity found with the given name.

get_interpolated_transform(entity: Entity, alpha: float)[source]
get_system(system_type: Type[System])[source]

Return the first system matching the given type, or None.

get_system_timings() Dict[str, float][source]

Return the latest per-system timing dict (system name → seconds).

groups: Dict[str, set[Entity]]
layers: List[str]
on_component_added(entity: Entity, component: Component)[source]
on_component_removed(entity: Entity, component: Component)[source]
on_entity_group_changed(entity: Entity, group: str, added: bool)[source]
on_entity_layer_changed(entity: Entity, old_layer: str, new_layer: str)[source]
physics_collision_matrix: Dict[str, List[str]]
physics_group_order: List[str]
query() EntityQuery[source]

Return a fluent query builder for filtering entities.

remove_system(system: System) bool[source]

Remove a system from the world. Returns True if removed.

render(dt: float, interpolation_alpha: float = 1.0)[source]
request_scene_change(scene_name: str)[source]

Request a scene change. The player loop will process this between frames.

simulate(dt: float)[source]
sync_interpolation_state()[source]
systems: List[System]
update(dt: float)[source]

core.event_system module

class core.event_system.EventSystem[source]

Bases: object

A simple event system that allows subscribing to and emitting events.

clear()[source]

Removes all listeners.

dispatch_pending()[source]
emit(event_name: str, *args, **kwargs)[source]

Queue an event. It will be dispatched by EventDispatchSystem on the next simulation tick (1-frame latency). :param event_name: Name of the event. :param args: Positional arguments to pass to callbacks. :param kwargs: Keyword arguments to pass to callbacks.

emit_immediate(event_name: str, *args, **kwargs)[source]

Emit an event and dispatch it synchronously to all current listeners right now, bypassing the queue. Use this when zero-latency delivery is required (e.g. damage events that must be processed in the same frame they are emitted). :param event_name: Name of the event. :param args: Positional arguments to pass to callbacks. :param kwargs: Keyword arguments to pass to callbacks.

has_listeners(event_name: str) bool[source]

Check if an event has any subscribers.

listener_count(event_name: str) int[source]

Return the number of subscribers for an event.

subscribe(event_name: str, callback: Callable)[source]

Subscribe to an event. :param event_name: Name of the event to listen for. :param callback: Function to call when event is emitted.

unsubscribe(event_name: str, callback: Callable) bool[source]

Unsubscribe from an event. :param event_name: Name of the event. :param callback: Function to remove. :return: True if the callback was removed, False if it was not found.

core.headless_server module

Headless server runner for AxisPy Engine.

Runs the game loop without any display, rendering, or audio. Only processes physics, scripts, and networking systems. Designed for dedicated game servers on Linux and Windows.

Usage:

python -m core.headless_server <scene_path> python core/headless_server.py <scene_path>

core.headless_server.main()[source]
core.headless_server.run_headless(scene_path: str, tick_rate: float = 60.0, verbose: bool = False)[source]

Run the engine in headless mode (no display, no rendering, no audio).

Parameters:
  • scene_path – Path to the .scn scene file to load.

  • tick_rate – Server tick rate in Hz (default 60).

  • verbose – If True, print periodic status info.

core.input module

class core.input.Input[source]

Bases: object

JOY_A = 0
JOY_B = 1
JOY_BACK = 6
JOY_L3 = 8
JOY_LB = 4
JOY_LEFT_X = 0
JOY_LEFT_Y = 1
JOY_LT = 4
JOY_R3 = 9
JOY_RB = 5
JOY_RIGHT_X = 2
JOY_RIGHT_Y = 3
JOY_RT = 5
JOY_START = 7
JOY_X = 2
JOY_Y = 3
classmethod clear_provider()[source]

Remove any injected provider, restoring default pygame input.

classmethod get_axis(axis_name: str) float[source]
classmethod get_events()[source]
classmethod get_game_mouse_position()[source]

Return mouse position mapped to game/design coordinates.

classmethod get_gesture() TouchGesture[source]

Return the recognized gesture data for the current frame.

classmethod get_joy_axis(axis: int, instance_id: int = -1) float[source]

Return axis value (-1..1) with deadzone applied.

classmethod get_joy_button(button: int, instance_id: int = -1) bool[source]

Return True if button is currently pressed.

classmethod get_joy_button_down(button: int, instance_id: int = -1) bool[source]

Return True if button was just pressed this frame.

classmethod get_joy_button_up(button: int, instance_id: int = -1) bool[source]

Return True if button was just released this frame.

classmethod get_joy_hat(hat: int = 0, instance_id: int = -1) tuple[source]

Return D-pad / hat value as (x, y) where x,y are -1, 0, or 1.

classmethod get_joystick_count() int[source]

Return number of connected joysticks.

classmethod get_joystick_ids() list[int][source]

Return list of connected joystick instance IDs.

classmethod get_joystick_name(instance_id: int = -1) str[source]

Return joystick name. If instance_id=-1, use first connected.

classmethod get_key(key_code)[source]
classmethod get_mouse_button(button_index)[source]
classmethod get_mouse_position()[source]
classmethod get_touch_count() int[source]

Return number of currently active touch points.

classmethod get_touches() dict[int, TouchPoint][source]

Return dict of all currently active touch points {finger_id: TouchPoint}.

classmethod get_touches_ended() list[TouchPoint][source]

Return list of touches that ended this frame.

classmethod get_touches_moved() list[TouchPoint][source]

Return list of touches that moved this frame.

classmethod get_touches_started() list[TouchPoint][source]

Return list of touches that began this frame.

classmethod is_touching() bool[source]

Return True if any finger is currently touching.

classmethod set_joystick_deadzone(deadzone: float)[source]

Set the deadzone threshold for joystick axes (default 0.15).

classmethod set_mouse_mapper(mapper_fn)[source]

Set a function (window_x, window_y) -> (game_x, game_y) or None.

classmethod set_provider(provider)[source]

Inject a provider object that overrides Input behaviour.

The provider may implement any subset of:

update(), get_key(key_code), get_mouse_button(index), get_mouse_position(), get_game_mouse_position(), get_events(), get_axis(name).

Missing methods fall through to the default pygame implementation. Pass None to restore the default behaviour.

classmethod update()[source]
class core.input.TouchGesture[source]

Bases: object

Holds recognized gesture data for the current frame.

double_tap
long_press
pinch
pinch_center
pinch_scale
rotate
rotate_angle
rotate_center
swipe
swipe_direction
swipe_velocity
tap
class core.input.TouchPoint(finger_id: int, x: float, y: float, dx: float = 0.0, dy: float = 0.0, pressure: float = 1.0)[source]

Bases: object

Represents a single touch point.

dx
dy
finger_id
pressure
x
y

core.input_map module

Named input action mapping.

Decouples gameplay logic from specific keys/buttons so rebinding is trivial.

Usage:

from core.input_map import InputMap
import pygame

# Register actions (typically at startup or from config)
InputMap.register("jump", [pygame.K_SPACE, pygame.K_w])
InputMap.register("fire", [pygame.K_f])

# Query in scripts
if InputMap.is_pressed("jump"):
    ...
if InputMap.is_just_pressed("jump"):
    ...

Actions can also be loaded from project.config via InputMap.load_from_config(config_dict) where the config contains:

{
    "input_actions": {
        "jump": [32, 119],
        "fire": [102]
    }
}
class core.input_map.InputMap[source]

Bases: object

Static action-to-key/button mapping registry.

classmethod clear()[source]

Remove all registered actions.

classmethod get_action_strength(action: str) float[source]

Return 1.0 if any key in action is pressed, else 0.0.

classmethod get_all_actions() dict[str, list[int]][source]

Return a copy of all registered actions.

classmethod get_bindings(action: str) list[int][source]

Return the key codes bound to action, or an empty list.

classmethod is_just_pressed(action: str) bool[source]

Return True if any key bound to action was pressed this frame.

classmethod is_just_released(action: str) bool[source]

Return True if any key bound to action was released this frame.

classmethod is_pressed(action: str) bool[source]

Return True if any key bound to action is currently held down.

classmethod load_from_config(config: dict)[source]

Load actions from a config dict containing an input_actions key.

Expected format:

{"input_actions": {"jump": [32, 119], "fire": [102]}}
classmethod register(action: str, keys: list[int])[source]

Register or overwrite an action with a list of key codes.

classmethod unregister(action: str)[source]

Remove an action.

classmethod update()[source]

Snapshot current keyboard state for just-pressed / just-released detection. Should be called once per frame after Input.update().

core.logger module

class core.logger.LogLevels[source]

Bases: object

DEBUG = 10
ERROR = 40
INFO = 20
WARNING = 30
classmethod name(level: int)[source]
classmethod parse(level: int | str)[source]
class core.logger.LogRecord(timestamp: 'str', level: 'str', level_value: 'int', subsystem: 'str', message: 'str', data: 'dict[str, Any]')[source]

Bases: object

data: dict[str, Any]
level: str
level_value: int
message: str
subsystem: str
timestamp: str
class core.logger.Logger(subsystem: str)[source]

Bases: object

debug(message: str, **data)[source]
error(message: str, **data)[source]
info(message: str, **data)[source]
warning(message: str, **data)[source]
core.logger.add_sink(sink: Callable[[LogRecord], None])[source]
core.logger.emit(level: int | str, subsystem: str, message: str, **data)[source]
core.logger.get_logger(subsystem: str)[source]
core.logger.get_min_level()[source]
core.logger.remove_sink(sink: Callable[[LogRecord], None])[source]
core.logger.set_min_level(level: int | str)[source]

core.object_pool module

Object pool for reusing deactivated entities instead of destroy/create churn.

class core.object_pool.ObjectPool(world: World, prefill: Dict[str, tuple[Callable[[], Entity], int]] | None = None)[source]

Bases: object

A per-World pool that recycles entities by a string tag.

Usage from scripts:

pool = ObjectPool(world, prefill={"bullet": (create_bullet, 20)})
bullet = pool.acquire("bullet")      # re-use or create
pool.release("bullet", bullet)        # deactivate and return to pool

Entities returned by acquire are shown (entity.show()) and have physics re-enabled. Entities passed to release are hidden and have physics disabled so they cost almost nothing while pooled.

acquire(tag: str) Entity | None[source]

Get an entity from the pool, or create one via the registered factory.

clear(tag: str | None = None)[source]

Destroy all pooled entities. If tag is None, clear every tag.

pool_size(tag: str) int[source]

Number of currently pooled (inactive) entities for tag.

register(tag: str, factory: Callable[[], Entity], prefill_count: int = 0)[source]

Register a factory for tag and optionally pre-create entities.

release(tag: str, entity: Entity)[source]

Return an entity to the pool for later reuse.

core.player module

class core.player.RuntimePlayer(scene_path: str | None = None, web_mode: bool = False)[source]

Bases: object

Encapsulates the runtime game loop, systems, and scene management.

build_collider_handles()[source]
draw_physics_debug()[source]
present_frame()[source]
async run()[source]
screen_to_world(window_x, window_y)[source]
update_collider_resize(mouse_pos)[source]
update_presentation_rect()[source]
window_to_render(window_x, window_y)[source]
world_to_screen(world_x, world_y)[source]
core.player.editor_print(*args, **kwargs)[source]

Print function that only outputs when running in editor mode.

core.player.run(scene_path=None)[source]

core.resources module

class core.resources.ResourceManager[source]

Bases: object

classmethod build_sprite_atlas_if_needed(force: bool = False, max_size: int = 2048, padding: int = 2) bool[source]
classmethod clear()[source]
classmethod load_image(path: str) Surface[source]
classmethod load_sound(path: str)[source]
classmethod load_sprite_atlas_manifest() bool[source]
classmethod portable_path(path: str) str[source]

Normalize a path to always use forward slashes for cross-platform storage.

classmethod prebuild_sprite_atlas(force: bool = False)[source]
classmethod preload_scene_assets(entities) dict[source]

Eagerly load all images, sounds, and fonts referenced by scene entities. Call this at scene load to avoid lazy-load hitches during gameplay. Returns a summary dict with counts of preloaded assets.

classmethod resolve_path(path: str) str[source]
classmethod restore(snap: dict)[source]

Restore a previously captured snapshot, replacing all current state.

classmethod set_base_path(path: str)[source]
classmethod set_headless(headless: bool = True)[source]

Enable headless mode: skip all image/sound/atlas loading.

classmethod slice_spritesheet(path: str, frame_width: int, frame_height: int, frame_count: int = 0, margin: int = 0, spacing: int = 0) list[Surface][source]
classmethod snapshot() dict[source]

Capture the current state of all caches for later restore(). Useful in unit tests to isolate resource side-effects.

classmethod to_os_path(path: str) str[source]

Convert a stored portable path (forward slashes) to native OS separators.

classmethod unload_image(path: str)[source]

Remove a single image from the cache.

classmethod unload_sound(path: str)[source]

Remove a single sound from the cache.

classmethod unload_unused(used_image_paths: set[str] = None, used_sound_paths: set[str] = None)[source]

Remove cached resources not in the provided sets. Useful between scene changes to free memory. Atlas surfaces are kept since they are shared across scenes.

core.runtime_launch module

class core.runtime_launch.LaunchHandle(process: 'subprocess.Popen', command: 'list[str]', scene_path: 'str', report_stdout_path: 'str', report_stderr_path: 'str', _stdout_file: 'Any' = None, _stderr_file: 'Any' = None, use_pipe: 'bool' = False)[source]

Bases: object

close_logs()[source]

Close the log file handles. Safe to call multiple times.

command: list[str]
process: Popen
report_stderr_path: str
report_stdout_path: str
scene_path: str
use_pipe: bool = False
class core.runtime_launch.LaunchProfile(module: 'str' = 'core.player', scene_file_name: 'str' = 'temp_scene.scn', working_directory: 'str' = '', report_directory: 'str' = '', python_executable: 'str' = '', extra_args: 'list[str]' = <factory>, python_path_entries: 'list[str]' = <factory>, env_overrides: 'dict[str, str]'=<factory>)[source]

Bases: object

env_overrides: dict[str, str]
extra_args: list[str]
module: str = 'core.player'
python_executable: str = ''
python_path_entries: list[str]
report_directory: str = ''
scene_file_name: str = 'temp_scene.scn'
working_directory: str = ''
class core.runtime_launch.RuntimeCommandBuilder[source]

Bases: object

classmethod build_command(profile: LaunchProfile, scene_path: str)[source]
classmethod launch(profile: LaunchProfile, scene_data: str, use_pipe: bool = False)[source]

core.save_manager module

Runtime save/load system for game state (save slots).

Usage from a user script:

from core.save_manager import SaveManager

class MyScript:
    def on_start(self):
        # Save the current world state to slot 1
        SaveManager.save(self.entity.world, "slot1")

        # Load from slot 1 (returns a new Scene)
        scene = SaveManager.load("slot1")

        # List available saves
        saves = SaveManager.list_saves()

        # Delete a save
        SaveManager.delete("slot1")

Save files are stored under <project_dir>/saves/<slot_name>.sav as JSON, using the same codec system as SceneSerializer.

class core.save_manager.SaveManager[source]

Bases: object

Static save/load manager for runtime game state.

classmethod delete(slot_name: str, project_dir: str = '') bool[source]

Delete a save slot file.

Returns:

True if deleted, False if not found or error.

classmethod exists(slot_name: str, project_dir: str = '') bool[source]

Check if a save slot exists.

classmethod list_saves(project_dir: str = '') list[dict][source]

Return info about all save files in the save directory.

Returns:

List of dicts with slot, timestamp, and path keys, sorted by most recent first.

classmethod load(slot_name: str, project_dir: str = '')[source]

Load a save file and return a reconstructed Scene.

Parameters:
  • slot_name – Name of the save slot.

  • project_dir – Base project directory.

Returns:

A Scene object on success, or None on failure.

classmethod load_extra(slot_name: str, project_dir: str = '') dict | None[source]

Load only the extra_data from a save file without reconstructing the scene.

Returns:

The extra data dict, or None if not found.

classmethod save(world, slot_name: str, project_dir: str = '', extra_data: dict | None = None) bool[source]

Serialize the current world state and write it to a save file.

Parameters:
  • world – The World instance to save.

  • slot_name – Name of the save slot (used as filename).

  • project_dir – Base project directory (for resolving save path).

  • extra_data – Optional dict of custom game data to include.

Returns:

True on success, False on failure.

save_directory: str = 'saves'

core.scene module

class core.scene.Scene(name: str = 'SampleScene')[source]

Bases: object

ensure_main_camera()[source]
setup_default()[source]
update(dt: float)[source]

core.scene_transition module

Scene transition effects — fade-out / fade-in overlay.

Usage from the player loop:

transition = SceneTransition(duration=0.5, color=(0, 0, 0))
transition.start_out()   # fade to black
# ... each frame:
transition.update(frame_dt)
transition.draw(surface)
if transition.is_done():
    # swap scene, then:
    transition.start_in()  # fade from black
class core.scene_transition.SceneTransition(duration: float = 0.4, color: tuple = (0, 0, 0))[source]

Bases: object

Simple full-screen colour overlay that fades in or out.

draw(surface: Surface)[source]

Draw the overlay on top of surface. No-op when fully transparent.

is_active() bool[source]
is_done() bool[source]
is_fade_in_done() bool[source]

True when a fade-in has completed (screen is fully transparent).

is_fade_out_done() bool[source]

True when a fade-out has completed (screen is fully opaque).

start_in()[source]

Begin fading from the overlay colour (screen appears).

start_out()[source]

Begin fading to the overlay colour (screen goes dark).

update(dt: float)[source]

core.serializer module

class core.serializer.SceneSerializer[source]

Bases: object

static entity_from_json(json_str: str, world: World) Entity[source]
static entity_to_json(entity: Entity) str[source]
static from_json(json_str: str) Scene[source]
static load_animation_clip(path: str) AnimationClip[source]
static load_animation_controller(path: str) AnimationController[source]
register_codec(component_type, to_data: Callable[[object], dict], from_data: Callable[[dict], object], component_name: str = None)[source]

Register a codec on this instance only (does not mutate class-level registry).

classmethod register_component_codec(component_type, to_data: Callable[[object], dict], from_data: Callable[[dict], object], component_name: str = None)[source]
classmethod register_component_codec_alias(alias_name: str, target_component_name: str)[source]
static save_animation_clip(path: str, clip: AnimationClip)[source]
static save_animation_controller(path: str, controller: AnimationController)[source]
static to_json(scene: Scene) str[source]

core.state_machine module

Finite State Machine for entity behavior management.

Usage from a user script:

from core.state_machine import StateMachine, State

class IdleState(State):
    def on_enter(self):
        print("Entering idle")
    def on_update(self, dt):
        if some_condition:
            self.machine.transition_to("walk")
    def on_exit(self):
        print("Leaving idle")

class WalkState(State):
    def on_enter(self):
        print("Starting to walk")
    def on_update(self, dt):
        if another_condition:
            self.machine.transition_to("idle")
    def on_exit(self):
        print("Stopped walking")

class MyScript:
    def on_start(self):
        self.state_machine = StateMachine(self.entity)
        self.state_machine.add_state("idle", IdleState())
        self.state_machine.add_state("walk", WalkState())
        self.state_machine.start("idle")

    def on_update(self, dt):
        self.state_machine.update(dt)
class core.state_machine.State[source]

Bases: object

Base class for FSM states. Override the lifecycle methods as needed.

on_enter()[source]

Called when this state becomes active.

on_exit()[source]

Called when leaving this state.

on_update(dt: float)[source]

Called every frame while this state is active.

class core.state_machine.StateMachine(entity=None)[source]

Bases: object

Simple finite state machine bound to an entity.

States are registered by name and transitions are triggered explicitly via transition_to(name).

add_state(name: str, state: State) None[source]

Register a state under name.

property current_state: str

Name of the currently active state, or empty string.

has_state(name: str) bool[source]
property previous_state: str

Name of the previously active state.

remove_state(name: str) None[source]

Remove a registered state. If it is the current state, exit it first.

start(name: str) None[source]

Set the initial state without calling on_exit on any previous state.

transition_to(name: str) None[source]

Transition from the current state to name.

update(dt: float) None[source]

Tick the current state. Call once per frame.

core.tween module

Tween/easing system for declarative property animation.

Usage from a user script:

class MyScript:
    def on_start(self):
        # Animate transform.x to 500 over 1 second with ease_out_cubic
        self.tween(self.entity, "transform.x", target=500, duration=1.0,
                   easing=ease_out_cubic)

        # Animate with explicit start value
        self.tween(self.entity, "transform.rotation", start=0, target=360,
                   duration=2.0, easing=ease_in_out_quad, loops=0)

The ScriptSystem ticks the tween manager each frame via TweenManager.tick(dt).

class core.tween.TweenManager[source]

Bases: object

Manages a set of active tweens. Typically one per entity or global.

cancel_all(entity=None)[source]

Cancel tweens. If entity is given, cancel only that entity’s tweens.

property count: int
tick(dt: float)[source]

Advance all tweens by dt seconds. Call once per frame.

tween(entity, attr_path: str, target: float, start: float | None = None, duration: float = 1.0, easing=None, on_complete=None, loops: int = 0, yoyo: bool = False)[source]

Create and register a new tween.

Parameters:
  • entity – The entity whose property to animate.

  • attr_path – Dotted path to the property, e.g. "transform.x".

  • target – Target value.

  • start – Start value. If None, the current value is read.

  • duration – Animation duration in seconds.

  • easing – Easing function (t) -> t. Defaults to ease_linear.

  • on_complete – Optional callback invoked when the tween finishes.

  • loops0 = play once, -1 = infinite, N = repeat N extra times.

  • yoyo – If True, alternates direction on each loop.

core.tween.ease_in_back(t: float) float[source]
core.tween.ease_in_bounce(t: float) float[source]
core.tween.ease_in_cubic(t: float) float[source]
core.tween.ease_in_elastic(t: float) float[source]
core.tween.ease_in_out_back(t: float) float[source]
core.tween.ease_in_out_bounce(t: float) float[source]
core.tween.ease_in_out_cubic(t: float) float[source]
core.tween.ease_in_out_elastic(t: float) float[source]
core.tween.ease_in_out_quad(t: float) float[source]
core.tween.ease_in_quad(t: float) float[source]
core.tween.ease_linear(t: float) float[source]
core.tween.ease_out_back(t: float) float[source]
core.tween.ease_out_bounce(t: float) float[source]
core.tween.ease_out_cubic(t: float) float[source]
core.tween.ease_out_elastic(t: float) float[source]
core.tween.ease_out_quad(t: float) float[source]

core.vector module

class core.vector.Vector2(x=0.0, y=0.0)[source]

Bases: object

angle()[source]
angle_to(other)[source]
copy()[source]
cross(other)[source]
distance_to(other)[source]
distance_to_squared(other)[source]
dot(other)[source]
classmethod down()[source]
classmethod left()[source]
lerp(other, t)[source]
magnitude()[source]
normalize()[source]
normalize_ip()[source]

Normalize this vector in-place. Returns self for chaining.

normalized()
classmethod one()[source]
reflect(normal)[source]
classmethod right()[source]
rotate(degrees)[source]
sqr_magnitude()[source]
classmethod up()[source]
x
y
classmethod zero()[source]

Module contents