core.components package
Submodules
core.components.animator module
core.components.camera module
- class core.components.camera.CameraComponent(active: bool = True, zoom: float = 1.0, rotation: float = 0.0, viewport_x: float = 0.0, viewport_y: float = 0.0, viewport_width: float = 1.0, viewport_height: float = 1.0, priority: int = 0, follow_target_id: str = '', follow_rotation: bool = True)[source]
Bases:
Component- DECAY_EXPONENTIAL = 'exponential'
- DECAY_LINEAR = 'linear'
- property is_shaking: bool
- shake(intensity: float = 5.0, duration: float = 0.3, decay: str = 'linear')[source]
Start a camera shake effect.
- Parameters:
intensity – Maximum pixel offset per axis.
duration – How long the shake lasts in seconds.
decay – Decay curve —
"linear"or"exponential".
- property shake_offset: tuple[float, float]
Current (x, y) shake offset in pixels.
core.components.colliders module
- class core.components.colliders.BoxCollider2D(width: float = None, height: float = None, offset_x: float = 0.0, offset_y: float = 0.0, is_trigger: bool = False, category_mask: int = 1, collision_mask: int = 4294967295, rotation: float = 0.0)[source]
Bases:
Component- property offset_x
- property offset_y
- class core.components.colliders.CircleCollider2D(radius: float = None, offset_x: float = 0.0, offset_y: float = 0.0, is_trigger: bool = False, category_mask: int = 1, collision_mask: int = 4294967295, rotation: float = 0.0)[source]
Bases:
Component- property offset_x
- property offset_y
- class core.components.colliders.PolygonCollider2D(points: list | None = None, offset_x: float = 0.0, offset_y: float = 0.0, rotation: float = 0.0, is_trigger: bool = False, category_mask: int = 1, collision_mask: int = 4294967295)[source]
Bases:
Component- property offset_x
- property offset_y
- property points
core.components.http_client module
- class core.components.http_client.HTTPClientComponent(base_url: str = '', default_headers: dict = None, timeout: float = 30.0, max_concurrent: int = 4)[source]
Bases:
ComponentPersistent HTTP client component for making async HTTP requests.
Uses a background thread pool to perform requests without blocking the game loop. Results are queued and retrieved via poll().
- Usage in scripts:
http = self.entity.get_component(HTTPClientComponent)
# GET request http.get(”https://api.example.com/data”, tag=”fetch_data”)
# POST request with JSON body http.post(”https://api.example.com/submit”,
body={“key”: “value”}, tag=”submit”)
# In on_update, poll for completed responses for response in http.poll():
- if response.ok:
data = response.json() print(f”[{response.tag}] Got: {data}”)
- else:
print(f”[{response.tag}] Error: {response.error}”)
- patch(url: str, body=None, headers: dict = None, tag: str = '')[source]
Perform an async PATCH request.
- poll() list[HTTPResponse][source]
Drain the response inbox. Call this in on_update. Returns a list of HTTPResponse objects for completed requests.
core.components.http_request module
- class core.components.http_request.HTTPRequestComponent(url: str = '', method: str = 'GET', request_body: str = '', content_type: str = 'application/json', timeout: float = 30.0, send_on_start: bool = False)[source]
Bases:
ComponentLightweight single-request component. Configure in the inspector or script, fire it, and poll for the result.
- Usage in scripts:
req = self.entity.get_component(HTTPRequestComponent)
# Configure and send req.url = “https://api.example.com/data” req.method = “GET” req.send()
# In on_update, check if done if req.is_done():
print(req.status_code, req.response_body) if req.ok:
data = req.json()
# Or send with body req.url = “https://api.example.com/submit” req.method = “POST” req.request_body = ‘{“key”: “value”}’ req.send()
- METHOD_DELETE = 'DELETE'
- METHOD_GET = 'GET'
- METHOD_PATCH = 'PATCH'
- METHOD_POST = 'POST'
- METHOD_PUT = 'PUT'
- property ok: bool
Return True if the last request was successful (2xx).
core.components.light module
2D Light components for point lights, spot lights, and light occluders.
Attach a PointLight2D or SpotLight2D to an entity with a Transform
to create a light source. Add LightOccluder2D to entities that should
block light and cast shadows.
The LightingSystem renders an ambient + light overlay each frame.
Usage:
entity = world.create_entity("torch")
entity.add_component(Transform(x=100, y=200))
entity.add_component(PointLight2D(color=(255, 200, 100), radius=300, intensity=1.0))
wall = world.create_entity("wall")
wall.add_component(Transform(x=300, y=200))
wall.add_component(LightOccluder2D(shape="box", width=50, height=200))
- class core.components.light.LightOccluder2D(shape: str = 'box', width: float = 50.0, height: float = 50.0, radius: float = 25.0, points: list | None = None, offset_x: float = 0.0, offset_y: float = 0.0, receive_light: bool = False, receive_shadow: bool = False, rotation: float = 0.0)[source]
Bases:
ComponentLight occluder that blocks light and casts shadows.
Supports three shape types: -
"box"— axis-aligned rectangle (width × height) -"circle"— circle defined by radius -"polygon"— arbitrary convex/concave polygon (list of Vector2 points)When added via the inspector with shape
"box"or"circle", the size is automatically derived from the entity’sSpriteRendererif present.- SHAPE_BOX = 'box'
- SHAPE_CIRCLE = 'circle'
- SHAPE_POLYGON = 'polygon'
- property points
- class core.components.light.PointLight2D(color: tuple = (255, 255, 255), radius: float = 200.0, intensity: float = 1.0, falloff: float = 2.0)[source]
Bases:
ComponentOmnidirectional 2D point light.
- class core.components.light.SpotLight2D(color: tuple = (255, 255, 255), radius: float = 300.0, intensity: float = 1.0, falloff: float = 2.0, angle: float = 0.0, cone_angle: float = 45.0, offset_x: float = 0.0, offset_y: float = 0.0)[source]
Bases:
ComponentDirectional 2D spot light with a cone angle.
core.components.multiplayer module
- class core.components.multiplayer.MultiplayerComponent(player_name: str = 'Player', max_players: int = 8, sync_rate: float = 20.0, port: int = 8765)[source]
Bases:
ComponentHigh-level multiplayer manager component.
Attach to a single entity (e.g. a GameManager) to manage multiplayer sessions. Uses a WebSocketComponent on the same entity for transport. Provides lobby management, player tracking, RPCs, and state sync.
- Modes:
“host”: Creates a WebSocket server, manages the room as authority.
“client”: Connects to a host’s WebSocket server.
- Usage in scripts:
mp = self.entity.get_component(MultiplayerComponent)
# Host a game mp.host_game(“MyRoom”)
# Or join a game mp.join_game(“ws://192.168.1.10:8765”, “PlayerName”)
# In on_update, pump the network mp.poll()
# Check players for player in mp.get_players():
print(player.name, player.is_ready)
# Set ready mp.set_ready(True)
# Start game (host only, when all ready) mp.start_game()
# Send RPC to all players mp.rpc(“take_damage”, {“amount”: 10})
# Send RPC to specific player mp.rpc_to(player_id, “heal”, {“amount”: 5})
# Send RPC to host only mp.rpc_to_host(“request_spawn”, {“prefab”: “bullet”})
# Send custom data mp.send_custom(“chat”, {“text”: “Hello!”})
# Listen for events (via global event system) self.subscribe_to_event(“mp_player_joined”, self.on_player_joined) self.subscribe_to_event(“mp_player_left”, self.on_player_left) self.subscribe_to_event(“mp_game_started”, self.on_game_started) self.subscribe_to_event(“mp_rpc”, self.on_rpc) self.subscribe_to_event(“mp_custom”, self.on_custom) self.subscribe_to_event(“mp_state_sync”, self.on_state_sync) self.subscribe_to_event(“mp_disconnected”, self.on_disconnected)
- MODE_CLIENT = 'client'
- MODE_HOST = 'host'
- host_game(room_name: str = 'Room')[source]
Start hosting a multiplayer game. Sets up WebSocket server.
- property is_active: bool
- property is_connected: bool
- property is_host: bool
- property local_player_id: str
- poll()[source]
Process incoming WebSocket messages. Call this in on_update. Emits global events for game scripts to handle.
- request_spawn(prefab_path: str, owner_id: str = '', data: dict = None)[source]
Host only: Request spawning a networked entity.
core.components.network_identity module
- class core.components.network_identity.NetworkIdentityComponent(network_id: str = '', owner_id: str = '', sync_transform: bool = True, sync_interval: float = 0.05, interpolate: bool = True)[source]
Bases:
ComponentMarks an entity as network-synchronized across multiplayer sessions.
Attach to any entity that should be replicated. Works with MultiplayerComponent on a manager entity to sync transform, custom properties, and ownership.
- Usage in scripts:
net_id = self.entity.get_component(NetworkIdentityComponent)
# Check ownership if net_id.is_mine():
# Only the owner should move this entity transform.x += speed * dt
# Set a synced variable (auto-replicated to all peers) net_id.set_var(“health”, 100) net_id.set_var(“score”, 42)
# Read synced variable health = net_id.get_var(“health”, default=100)
# Transfer ownership (host authority) net_id.transfer_ownership(new_player_id)
- Auto-sync behavior:
Transform (x, y, rotation) is synced automatically based on sync_transform flag.
Custom variables set via set_var() are synced when changed.
Sync happens at the rate configured on the MultiplayerComponent.
core.components.particle_emitter module
- class core.components.particle_emitter.ParticleEmitterComponent(emitting: bool = True, one_shot: bool = False, local_space: bool = False, render_layer: str = 'front', blend_additive: bool = False, max_particles: int = 512, emission_rate: float = 0.0, burst_count: int = 0, burst_interval: float = 1.0, lifetime_min: float = 0.25, lifetime_max: float = 0.75, speed_min: float = 30.0, speed_max: float = 90.0, direction_degrees: float = 270.0, spread_degrees: float = 360.0, gravity_x: float = 0.0, gravity_y: float = 0.0, damping: float = 0.0, radial_offset_min: float = 0.0, radial_offset_max: float = 0.0, angular_velocity_min: float = 0.0, angular_velocity_max: float = 0.0, start_size_min: float = 4.0, start_size_max: float = 10.0, end_size_min: float = 0.0, end_size_max: float = 2.0, start_color: tuple[int, int, int, int] = (255, 180, 80, 255), end_color: tuple[int, int, int, int] = (200, 60, 10, 0), emitter_lifetime: float = -1.0, shape: str = 'circle')[source]
Bases:
Component- LAYER_BEHIND = 'behind'
- LAYER_FRONT = 'front'
- SHAPE_CIRCLE = 'circle'
- SHAPE_PIXEL = 'pixel'
- SHAPE_SQUARE = 'square'
core.components.rigidbody module
- class core.components.rigidbody.Rigidbody2D(velocity_x: float = 0.0, velocity_y: float = 0.0, mass: float = 1.0, angular_velocity: float = 0.0, gravity_scale: float = 1.0, use_gravity: bool = True, body_type: str = 'dynamic', is_kinematic: bool = False, restitution: float = 0.0, friction: float = 0.0, linear_damping: float = 0.0, angular_damping: float = 0.0, freeze_rotation: bool = False)[source]
Bases:
Component- BODY_TYPE_DYNAMIC = 'dynamic'
- BODY_TYPE_KINEMATIC = 'kinematic'
- BODY_TYPE_STATIC = 'static'
- property body_type
- property can_rotate
- property elasticity
- property force_x
- property force_y
- property is_dynamic
- property is_kinematic
- property is_static
- property torque
- property velocity_x
- property velocity_y
core.components.script module
- class core.components.script.ScriptComponent(script_path: str = '', class_name: str = '')[source]
Bases:
ComponentComponent for attaching Python scripts to entities.
Scripts automatically receive the following injected attributes: - entity: The entity this script is attached to - logger: A logger instance with the name “script.<ClassName>”
Example
- class MyScript:
- def on_start(self):
# logger is automatically available! self.logger.info(“Script started”) print(self.entity.name) # entity is also available
- call_group(group_name: str, method_name: str, *args, **kwargs)[source]
Calls a method on all script components of entities in the specified group.
- emit_global_event(event_name: str, *args, **kwargs)[source]
Emit an event globally to the World (queued, 1-frame latency).
- emit_global_event_immediate(event_name: str, *args, **kwargs)[source]
Emit an event globally and dispatch it synchronously (zero latency).
- emit_local_event(event_name: str, *args, **kwargs)[source]
Emit an event on this entity (queued, 1-frame latency).
- emit_local_event_immediate(event_name: str, *args, **kwargs)[source]
Emit an event on this entity and dispatch it synchronously (zero latency).
- instantiate_prefab(prefab_path: str, parent=None, name: str = None, x: float = None, y: float = None, rotation: float = None, scale_x: float = None, scale_y: float = None)[source]
- spawn_prefab(prefab_path: str, parent=None, name: str = None, x: float = None, y: float = None, rotation: float = None, scale_x: float = None, scale_y: float = None)[source]
- subscribe_to_event(event_name: str, callback, target_entity=None)[source]
Subscribe to an event. :param event_name: Name of the event. :param callback: Method to call. :param target_entity: If provided, subscribes to that entity’s event.
If None, subscribes to the global World event.
- tick_coroutines(dt: float)[source]
Advance all coroutines by dt. Called by ScriptSystem each frame.
core.components.sound module
core.components.sprite_renderer module
core.components.steering module
- class core.components.steering.AlignmentBehavior(weight: float = 1.0, neighbor_radius: float = 100.0)[source]
Bases:
ComponentSteer to match the average heading of neighbours.
- class core.components.steering.ArriveBehavior(target_x: float = 0.0, target_y: float = 0.0, weight: float = 1.0, slow_radius: float = 100.0)[source]
Bases:
ComponentSteer towards a target, decelerating smoothly within slow_radius.
- class core.components.steering.CohesionBehavior(weight: float = 1.0, neighbor_radius: float = 100.0)[source]
Bases:
ComponentSteer towards the average position of neighbours.
- class core.components.steering.FleeBehavior(target_x: float = 0.0, target_y: float = 0.0, weight: float = 1.0, panic_distance: float = 200.0)[source]
Bases:
ComponentSteer away from a target position.
- class core.components.steering.SeekBehavior(target_x: float = 0.0, target_y: float = 0.0, weight: float = 1.0)[source]
Bases:
ComponentSteer towards a target position.
- class core.components.steering.SeparationBehavior(weight: float = 1.0, neighbor_radius: float = 50.0)[source]
Bases:
ComponentSteer to avoid crowding neighbours within neighbor_radius.
- class core.components.steering.SteeringAgentComponent(max_speed: float = 150.0, max_force: float = 300.0, mass: float = 1.0, drag: float = 0.0)[source]
Bases:
ComponentCore steering agent. Accumulates forces from behaviour components and applies the resulting velocity to the entity’s Transform each frame.
core.components.tilemap module
- class core.components.tilemap.TileLayer(name: 'str' = 'Layer', width: 'int' = 10, height: 'int' = 10, tiles: 'List[int]' = <factory>, visible: 'bool' = True, offset_x: 'int' = 0, offset_y: 'int' = 0)[source]
Bases:
object- array_to_world(array_x: int, array_y: int) tuple[int, int][source]
Convert array indices to world coordinates
- expand_to_include(world_x: int, world_y: int)[source]
Expand the tilemap to include the given world coordinate
- height: int = 10
- name: str = 'Layer'
- offset_x: int = 0
- offset_y: int = 0
- resize_with_offset(new_width: int, new_height: int, new_offset_x: int, new_offset_y: int)[source]
Resize the tilemap with a new offset
- set_world(world_x: int, world_y: int, value: int)[source]
Set tile value at world coordinates, expanding if necessary
- tiles: List[int]
- visible: bool = True
- width: int = 10
- class core.components.tilemap.TilemapComponent(map_width: int = 20, map_height: int = 15, tileset: Tileset | None = None, cell_width: int | None = None, cell_height: int | None = None, layers: List[TileLayer] | None = None)[source]
Bases:
ComponentSpritesheet-based tilemap.
Coordinates: - Tile coordinates are (0..width-1, 0..height-1) - World origin is the parent entity Transform center by convention; editor treats tilemap origin as top-left.
Rendering uses the entity Transform as an anchor, see render system for details.
core.components.timer module
- class core.components.timer.TimerComponent(duration: float = 1.0, one_shot: bool = True, autostart: bool = False, callback=None)[source]
Bases:
ComponentA simple timer component for user scripts.
Usage from a script:
timer = self.entity.add_component(TimerComponent( duration=2.0, one_shot=True, autostart=True, callback=self.on_timer_done, ))
Or create and start later:
timer = self.entity.add_component(TimerComponent(duration=1.5)) timer.start()
The callback is invoked each time the timer expires. For repeating timers (
one_shot=False), it fires everydurationseconds.- property elapsed: float
- property is_finished: bool
- property is_running: bool
- property time_left: float
core.components.transform module
core.components.ui module
- class core.components.ui.ButtonComponent(text='Button', width=100.0, height=40.0, normal_color=(100, 100, 100), hover_color=(150, 150, 150), pressed_color=(50, 50, 50), text_color=(255, 255, 255))[source]
Bases:
UIComponent
- class core.components.ui.CheckBoxComponent(checked=False, size=20.0, checked_color=(0, 200, 0), unchecked_color=(200, 200, 200))[source]
Bases:
UIComponent
- class core.components.ui.GridBoxContainerComponent(columns=2, spacing_x=5.0, spacing_y=5.0)[source]
Bases:
UIComponent
- class core.components.ui.HBoxContainerComponent(spacing=5.0)[source]
Bases:
UIComponent
- class core.components.ui.ImageRenderer(image_path=None, color=(255, 255, 255), width=50.0, height=50.0)[source]
Bases:
UIComponent
- class core.components.ui.ProgressBarComponent(value=0.5, min_value=0.0, max_value=1.0, width=200.0, height=20.0, bg_color=(100, 100, 100), fill_color=(0, 200, 0))[source]
Bases:
UIComponent
- class core.components.ui.SliderComponent(value=0.0, min_value=0.0, max_value=1.0, width=200.0, height=20.0, track_color=(100, 100, 100), handle_color=(200, 200, 200))[source]
Bases:
UIComponent
- class core.components.ui.TextInputComponent(text='', placeholder='Enter text...', width=200.0, height=30.0, bg_color=(255, 255, 255), text_color=(0, 0, 0))[source]
Bases:
UIComponent
- class core.components.ui.TextRenderer(text='Text', font_size=24, color=(255, 255, 255), font_path=None)[source]
Bases:
UIComponent
- class core.components.ui.VBoxContainerComponent(spacing=5.0)[source]
Bases:
UIComponent
core.components.webrtc module
- class core.components.webrtc.WebRTCComponent(ice_servers: str = 'stun:stun.l.google.com:19302', data_channel_label: str = 'game', ordered: bool = True, max_retransmits: int = -1, autostart: bool = False, max_queue_size: int = 1024)[source]
Bases:
ComponentWebRTC component for peer-to-peer data channel communication.
Supports creating and joining peer connections with data channels for low-latency game networking. Uses aiortc under the hood. A signaling mechanism (e.g. WebSocket) is needed to exchange offers/answers/ICE candidates between peers.
- Usage in scripts:
rtc = self.entity.get_component(WebRTCComponent)
# Create an offer (caller side) rtc.create_offer()
# Poll for signaling data to send to the remote peer for sender, msg in rtc.poll():
- if sender == “local”:
# msg is a dict like {“type”: “offer”, “sdp”: “…”} or # {“type”: “candidate”, …} # Send this to the remote peer via your signaling channel ws.send_json(msg)
# On the remote side, set the remote description from received signaling rtc.set_remote_description(offer_dict) # triggers answer creation
# Feed ICE candidates from the remote peer rtc.add_ice_candidate(candidate_dict)
# Send data over the data channel rtc.send(“Hello peer!”) rtc.send_json({“action”: “move”, “x”: 10})
# Poll for incoming data channel messages for sender, msg in rtc.poll():
- if sender == “datachannel”:
print(“Received:”, msg)
# Close rtc.close()
- add_ice_candidate(candidate_dict: dict)[source]
Add an ICE candidate received from the signaling channel. candidate_dict should have keys like “candidate”, “sdpMid”, “sdpMLineIndex”.
- create_answer()[source]
Create an SDP answer (callee side). Results appear in poll() as local signaling.
- create_offer()[source]
Create an SDP offer (caller side). Results appear in poll() as local signaling.
- poll() list[tuple][source]
Drain the inbox and return a list of (sender, message) tuples. Call this in on_update.
- Sender types:
- “local”: signaling data to forward to the remote peer
(offer, answer, or ICE candidate dicts)
“datachannel”: data received from the remote peer
- “system”: connection state events like
{“event”: “connected”}, {“event”: “disconnected”}, {“event”: “error”, “message”: “…”}
core.components.websocket module
- class core.components.websocket.WebSocketComponent(mode: str = 'client', host: str = 'localhost', port: int = 8765, url: str = '', autostart: bool = False, max_queue_size: int = 1024)[source]
Bases:
ComponentWebSocket component supporting both server and client modes.
- Modes:
“server”: Listens on host:port, accepts client connections.
“client”: Connects to a remote WebSocket server.
- Usage in scripts:
# Access the component ws = self.entity.get_component(WebSocketComponent)
# Start the connection (call once, e.g. in on_start) ws.start()
# In on_update, poll for incoming messages for sender, message in ws.poll():
print(f”Received: {message}”)
# Send data ws.send(“Hello”) # Client: send to server. Server: broadcast to all. ws.send_json({“key”: “val”}) # Send a JSON-serializable dict. ws.broadcast(“Hi everyone”) # Server only: broadcast to all clients. ws.send_to(client_id, “Hi”) # Server only: send to a specific client.
# Stop cleanly ws.stop()
- MODE_CLIENT = 'client'
- MODE_SERVER = 'server'
- poll() list[tuple][source]
Drain the inbox and return a list of (sender, message) tuples. Call this in on_update to process incoming messages on the game thread.
For server mode, sender is the client_id (int). For client mode, sender is “server”. Connection/disconnection events use sender “system” with message dicts like {“event”: “connected”, “client_id”: id} or {“event”: “disconnected”, “client_id”: id}.
- send(message: str)[source]
Client mode: Send a message to the server. Server mode: Broadcast a message to all connected clients.
core.components.webview module
- class core.components.webview.WebviewComponent(url: str = '', title: str = 'Webview', width: int = 800, height: int = 600, resizable: bool = True, frameless: bool = False, autoopen: bool = False)[source]
Bases:
ComponentWebview component that opens a native browser window using pywebview.
Supports loading a URL or raw HTML content. The webview runs in a background thread so it doesn’t block the game loop. Communication between the game and webview is done via message queues.
- Usage in scripts:
wv = self.entity.get_component(WebviewComponent)
# Open a URL wv.open()
# Or open with specific URL wv.url = “https://example.com” wv.open()
# Load raw HTML wv.load_html(“<h1>Hello from engine!</h1>”)
# Evaluate JavaScript in the webview wv.evaluate_js(“document.title”)
# Poll for JS evaluation results in on_update for result in wv.poll():
print(“JS result:”, result)
# Close the webview wv.close()
- evaluate_js(script: str)[source]
Evaluate JavaScript in the webview. Results are queued and retrieved via poll().
Module contents
- class core.components.AlignmentBehavior(weight: float = 1.0, neighbor_radius: float = 100.0)[source]
Bases:
ComponentSteer to match the average heading of neighbours.
- class core.components.AnimatorComponent(controller_path: str = None, play_on_start: bool = True, speed: float = 1.0)[source]
Bases:
Component
- class core.components.ArriveBehavior(target_x: float = 0.0, target_y: float = 0.0, weight: float = 1.0, slow_radius: float = 100.0)[source]
Bases:
ComponentSteer towards a target, decelerating smoothly within slow_radius.
- class core.components.BoxCollider2D(width: float = None, height: float = None, offset_x: float = 0.0, offset_y: float = 0.0, is_trigger: bool = False, category_mask: int = 1, collision_mask: int = 4294967295, rotation: float = 0.0)[source]
Bases:
Component- property offset_x
- property offset_y
- class core.components.ButtonComponent(text='Button', width=100.0, height=40.0, normal_color=(100, 100, 100), hover_color=(150, 150, 150), pressed_color=(50, 50, 50), text_color=(255, 255, 255))[source]
Bases:
UIComponent
- class core.components.CameraComponent(active: bool = True, zoom: float = 1.0, rotation: float = 0.0, viewport_x: float = 0.0, viewport_y: float = 0.0, viewport_width: float = 1.0, viewport_height: float = 1.0, priority: int = 0, follow_target_id: str = '', follow_rotation: bool = True)[source]
Bases:
Component- DECAY_EXPONENTIAL = 'exponential'
- DECAY_LINEAR = 'linear'
- property is_shaking: bool
- shake(intensity: float = 5.0, duration: float = 0.3, decay: str = 'linear')[source]
Start a camera shake effect.
- Parameters:
intensity – Maximum pixel offset per axis.
duration – How long the shake lasts in seconds.
decay – Decay curve —
"linear"or"exponential".
- property shake_offset: tuple[float, float]
Current (x, y) shake offset in pixels.
- class core.components.CheckBoxComponent(checked=False, size=20.0, checked_color=(0, 200, 0), unchecked_color=(200, 200, 200))[source]
Bases:
UIComponent
- class core.components.CircleCollider2D(radius: float = None, offset_x: float = 0.0, offset_y: float = 0.0, is_trigger: bool = False, category_mask: int = 1, collision_mask: int = 4294967295, rotation: float = 0.0)[source]
Bases:
Component- property offset_x
- property offset_y
- class core.components.CohesionBehavior(weight: float = 1.0, neighbor_radius: float = 100.0)[source]
Bases:
ComponentSteer towards the average position of neighbours.
- class core.components.FleeBehavior(target_x: float = 0.0, target_y: float = 0.0, weight: float = 1.0, panic_distance: float = 200.0)[source]
Bases:
ComponentSteer away from a target position.
- class core.components.GridBoxContainerComponent(columns=2, spacing_x=5.0, spacing_y=5.0)[source]
Bases:
UIComponent
- class core.components.HBoxContainerComponent(spacing=5.0)[source]
Bases:
UIComponent
- class core.components.HTTPClientComponent(base_url: str = '', default_headers: dict = None, timeout: float = 30.0, max_concurrent: int = 4)[source]
Bases:
ComponentPersistent HTTP client component for making async HTTP requests.
Uses a background thread pool to perform requests without blocking the game loop. Results are queued and retrieved via poll().
- Usage in scripts:
http = self.entity.get_component(HTTPClientComponent)
# GET request http.get(”https://api.example.com/data”, tag=”fetch_data”)
# POST request with JSON body http.post(”https://api.example.com/submit”,
body={“key”: “value”}, tag=”submit”)
# In on_update, poll for completed responses for response in http.poll():
- if response.ok:
data = response.json() print(f”[{response.tag}] Got: {data}”)
- else:
print(f”[{response.tag}] Error: {response.error}”)
- patch(url: str, body=None, headers: dict = None, tag: str = '')[source]
Perform an async PATCH request.
- poll() list[HTTPResponse][source]
Drain the response inbox. Call this in on_update. Returns a list of HTTPResponse objects for completed requests.
- class core.components.HTTPRequestComponent(url: str = '', method: str = 'GET', request_body: str = '', content_type: str = 'application/json', timeout: float = 30.0, send_on_start: bool = False)[source]
Bases:
ComponentLightweight single-request component. Configure in the inspector or script, fire it, and poll for the result.
- Usage in scripts:
req = self.entity.get_component(HTTPRequestComponent)
# Configure and send req.url = “https://api.example.com/data” req.method = “GET” req.send()
# In on_update, check if done if req.is_done():
print(req.status_code, req.response_body) if req.ok:
data = req.json()
# Or send with body req.url = “https://api.example.com/submit” req.method = “POST” req.request_body = ‘{“key”: “value”}’ req.send()
- METHOD_DELETE = 'DELETE'
- METHOD_GET = 'GET'
- METHOD_PATCH = 'PATCH'
- METHOD_POST = 'POST'
- METHOD_PUT = 'PUT'
- error: str
- headers: dict
- property ok: bool
Return True if the last request was successful (2xx).
- response_body: str
- response_headers: dict
- status_code: int
- class core.components.LightOccluder2D(shape: str = 'box', width: float = 50.0, height: float = 50.0, radius: float = 25.0, points: list | None = None, offset_x: float = 0.0, offset_y: float = 0.0, receive_light: bool = False, receive_shadow: bool = False, rotation: float = 0.0)[source]
Bases:
ComponentLight occluder that blocks light and casts shadows.
Supports three shape types: -
"box"— axis-aligned rectangle (width × height) -"circle"— circle defined by radius -"polygon"— arbitrary convex/concave polygon (list of Vector2 points)When added via the inspector with shape
"box"or"circle", the size is automatically derived from the entity’sSpriteRendererif present.- SHAPE_BOX = 'box'
- SHAPE_CIRCLE = 'circle'
- SHAPE_POLYGON = 'polygon'
- property points
- class core.components.MultiplayerComponent(player_name: str = 'Player', max_players: int = 8, sync_rate: float = 20.0, port: int = 8765)[source]
Bases:
ComponentHigh-level multiplayer manager component.
Attach to a single entity (e.g. a GameManager) to manage multiplayer sessions. Uses a WebSocketComponent on the same entity for transport. Provides lobby management, player tracking, RPCs, and state sync.
- Modes:
“host”: Creates a WebSocket server, manages the room as authority.
“client”: Connects to a host’s WebSocket server.
- Usage in scripts:
mp = self.entity.get_component(MultiplayerComponent)
# Host a game mp.host_game(“MyRoom”)
# Or join a game mp.join_game(“ws://192.168.1.10:8765”, “PlayerName”)
# In on_update, pump the network mp.poll()
# Check players for player in mp.get_players():
print(player.name, player.is_ready)
# Set ready mp.set_ready(True)
# Start game (host only, when all ready) mp.start_game()
# Send RPC to all players mp.rpc(“take_damage”, {“amount”: 10})
# Send RPC to specific player mp.rpc_to(player_id, “heal”, {“amount”: 5})
# Send RPC to host only mp.rpc_to_host(“request_spawn”, {“prefab”: “bullet”})
# Send custom data mp.send_custom(“chat”, {“text”: “Hello!”})
# Listen for events (via global event system) self.subscribe_to_event(“mp_player_joined”, self.on_player_joined) self.subscribe_to_event(“mp_player_left”, self.on_player_left) self.subscribe_to_event(“mp_game_started”, self.on_game_started) self.subscribe_to_event(“mp_rpc”, self.on_rpc) self.subscribe_to_event(“mp_custom”, self.on_custom) self.subscribe_to_event(“mp_state_sync”, self.on_state_sync) self.subscribe_to_event(“mp_disconnected”, self.on_disconnected)
- MODE_CLIENT = 'client'
- MODE_HOST = 'host'
- host_game(room_name: str = 'Room')[source]
Start hosting a multiplayer game. Sets up WebSocket server.
- property is_active: bool
- property is_connected: bool
- property is_host: bool
- property local_player_id: str
- poll()[source]
Process incoming WebSocket messages. Call this in on_update. Emits global events for game scripts to handle.
- request_spawn(prefab_path: str, owner_id: str = '', data: dict = None)[source]
Host only: Request spawning a networked entity.
- class core.components.NetworkIdentityComponent(network_id: str = '', owner_id: str = '', sync_transform: bool = True, sync_interval: float = 0.05, interpolate: bool = True)[source]
Bases:
ComponentMarks an entity as network-synchronized across multiplayer sessions.
Attach to any entity that should be replicated. Works with MultiplayerComponent on a manager entity to sync transform, custom properties, and ownership.
- Usage in scripts:
net_id = self.entity.get_component(NetworkIdentityComponent)
# Check ownership if net_id.is_mine():
# Only the owner should move this entity transform.x += speed * dt
# Set a synced variable (auto-replicated to all peers) net_id.set_var(“health”, 100) net_id.set_var(“score”, 42)
# Read synced variable health = net_id.get_var(“health”, default=100)
# Transfer ownership (host authority) net_id.transfer_ownership(new_player_id)
- Auto-sync behavior:
Transform (x, y, rotation) is synced automatically based on sync_transform flag.
Custom variables set via set_var() are synced when changed.
Sync happens at the rate configured on the MultiplayerComponent.
- class core.components.ParticleEmitterComponent(emitting: bool = True, one_shot: bool = False, local_space: bool = False, render_layer: str = 'front', blend_additive: bool = False, max_particles: int = 512, emission_rate: float = 0.0, burst_count: int = 0, burst_interval: float = 1.0, lifetime_min: float = 0.25, lifetime_max: float = 0.75, speed_min: float = 30.0, speed_max: float = 90.0, direction_degrees: float = 270.0, spread_degrees: float = 360.0, gravity_x: float = 0.0, gravity_y: float = 0.0, damping: float = 0.0, radial_offset_min: float = 0.0, radial_offset_max: float = 0.0, angular_velocity_min: float = 0.0, angular_velocity_max: float = 0.0, start_size_min: float = 4.0, start_size_max: float = 10.0, end_size_min: float = 0.0, end_size_max: float = 2.0, start_color: tuple[int, int, int, int] = (255, 180, 80, 255), end_color: tuple[int, int, int, int] = (200, 60, 10, 0), emitter_lifetime: float = -1.0, shape: str = 'circle')[source]
Bases:
Component- LAYER_BEHIND = 'behind'
- LAYER_FRONT = 'front'
- SHAPE_CIRCLE = 'circle'
- SHAPE_PIXEL = 'pixel'
- SHAPE_SQUARE = 'square'
- class core.components.PointLight2D(color: tuple = (255, 255, 255), radius: float = 200.0, intensity: float = 1.0, falloff: float = 2.0)[source]
Bases:
ComponentOmnidirectional 2D point light.
- class core.components.PolygonCollider2D(points: list | None = None, offset_x: float = 0.0, offset_y: float = 0.0, rotation: float = 0.0, is_trigger: bool = False, category_mask: int = 1, collision_mask: int = 4294967295)[source]
Bases:
Component- property offset_x
- property offset_y
- property points
- class core.components.ProgressBarComponent(value=0.5, min_value=0.0, max_value=1.0, width=200.0, height=20.0, bg_color=(100, 100, 100), fill_color=(0, 200, 0))[source]
Bases:
UIComponent
- class core.components.Rigidbody2D(velocity_x: float = 0.0, velocity_y: float = 0.0, mass: float = 1.0, angular_velocity: float = 0.0, gravity_scale: float = 1.0, use_gravity: bool = True, body_type: str = 'dynamic', is_kinematic: bool = False, restitution: float = 0.0, friction: float = 0.0, linear_damping: float = 0.0, angular_damping: float = 0.0, freeze_rotation: bool = False)[source]
Bases:
Component- BODY_TYPE_DYNAMIC = 'dynamic'
- BODY_TYPE_KINEMATIC = 'kinematic'
- BODY_TYPE_STATIC = 'static'
- property body_type
- property can_rotate
- property elasticity
- property force_x
- property force_y
- property is_dynamic
- property is_kinematic
- property is_static
- property torque
- property velocity_x
- property velocity_y
- class core.components.ScriptComponent(script_path: str = '', class_name: str = '')[source]
Bases:
ComponentComponent for attaching Python scripts to entities.
Scripts automatically receive the following injected attributes: - entity: The entity this script is attached to - logger: A logger instance with the name “script.<ClassName>”
Example
- class MyScript:
- def on_start(self):
# logger is automatically available! self.logger.info(“Script started”) print(self.entity.name) # entity is also available
- call_group(group_name: str, method_name: str, *args, **kwargs)[source]
Calls a method on all script components of entities in the specified group.
- emit_global_event(event_name: str, *args, **kwargs)[source]
Emit an event globally to the World (queued, 1-frame latency).
- emit_global_event_immediate(event_name: str, *args, **kwargs)[source]
Emit an event globally and dispatch it synchronously (zero latency).
- emit_local_event(event_name: str, *args, **kwargs)[source]
Emit an event on this entity (queued, 1-frame latency).
- emit_local_event_immediate(event_name: str, *args, **kwargs)[source]
Emit an event on this entity and dispatch it synchronously (zero latency).
- instantiate_prefab(prefab_path: str, parent=None, name: str = None, x: float = None, y: float = None, rotation: float = None, scale_x: float = None, scale_y: float = None)[source]
- spawn_prefab(prefab_path: str, parent=None, name: str = None, x: float = None, y: float = None, rotation: float = None, scale_x: float = None, scale_y: float = None)[source]
- subscribe_to_event(event_name: str, callback, target_entity=None)[source]
Subscribe to an event. :param event_name: Name of the event. :param callback: Method to call. :param target_entity: If provided, subscribes to that entity’s event.
If None, subscribes to the global World event.
- tick_coroutines(dt: float)[source]
Advance all coroutines by dt. Called by ScriptSystem each frame.
- class core.components.SeekBehavior(target_x: float = 0.0, target_y: float = 0.0, weight: float = 1.0)[source]
Bases:
ComponentSteer towards a target position.
- class core.components.SeparationBehavior(weight: float = 1.0, neighbor_radius: float = 50.0)[source]
Bases:
ComponentSteer to avoid crowding neighbours within neighbor_radius.
- class core.components.SliderComponent(value=0.0, min_value=0.0, max_value=1.0, width=200.0, height=20.0, track_color=(100, 100, 100), handle_color=(200, 200, 200))[source]
Bases:
UIComponent
- class core.components.SoundComponent(file_path='', volume=1.0, loop=False, is_music=False, autoplay=False, spatialize=True, min_distance=0.0, max_distance=600.0, pan_distance=300.0)[source]
Bases:
Component
- class core.components.SpotLight2D(color: tuple = (255, 255, 255), radius: float = 300.0, intensity: float = 1.0, falloff: float = 2.0, angle: float = 0.0, cone_angle: float = 45.0, offset_x: float = 0.0, offset_y: float = 0.0)[source]
Bases:
ComponentDirectional 2D spot light with a cone angle.
- class core.components.SpriteRenderer(color=(255, 255, 255), width=50, height=50, image_path=None)[source]
Bases:
Component- property height
- property width
- class core.components.SteeringAgentComponent(max_speed: float = 150.0, max_force: float = 300.0, mass: float = 1.0, drag: float = 0.0)[source]
Bases:
ComponentCore steering agent. Accumulates forces from behaviour components and applies the resulting velocity to the entity’s Transform each frame.
- class core.components.TextInputComponent(text='', placeholder='Enter text...', width=200.0, height=30.0, bg_color=(255, 255, 255), text_color=(0, 0, 0))[source]
Bases:
UIComponent
- class core.components.TextRenderer(text='Text', font_size=24, color=(255, 255, 255), font_path=None)[source]
Bases:
UIComponent
- class core.components.TileLayer(name: 'str' = 'Layer', width: 'int' = 10, height: 'int' = 10, tiles: 'List[int]' = <factory>, visible: 'bool' = True, offset_x: 'int' = 0, offset_y: 'int' = 0)[source]
Bases:
object- array_to_world(array_x: int, array_y: int) tuple[int, int][source]
Convert array indices to world coordinates
- expand_to_include(world_x: int, world_y: int)[source]
Expand the tilemap to include the given world coordinate
- height: int = 10
- name: str = 'Layer'
- offset_x: int = 0
- offset_y: int = 0
- resize_with_offset(new_width: int, new_height: int, new_offset_x: int, new_offset_y: int)[source]
Resize the tilemap with a new offset
- set_world(world_x: int, world_y: int, value: int)[source]
Set tile value at world coordinates, expanding if necessary
- tiles: List[int]
- visible: bool = True
- width: int = 10
- class core.components.TilemapComponent(map_width: int = 20, map_height: int = 15, tileset: Tileset | None = None, cell_width: int | None = None, cell_height: int | None = None, layers: List[TileLayer] | None = None)[source]
Bases:
ComponentSpritesheet-based tilemap.
Coordinates: - Tile coordinates are (0..width-1, 0..height-1) - World origin is the parent entity Transform center by convention; editor treats tilemap origin as top-left.
Rendering uses the entity Transform as an anchor, see render system for details.
- class core.components.Tileset(image_path: 'str' = '', tile_width: 'int' = 32, tile_height: 'int' = 32, spacing: 'int' = 0, margin: 'int' = 0)[source]
Bases:
object- image_path: str = ''
- margin: int = 0
- spacing: int = 0
- tile_height: int = 32
- tile_width: int = 32
- class core.components.TimerComponent(duration: float = 1.0, one_shot: bool = True, autostart: bool = False, callback=None)[source]
Bases:
ComponentA simple timer component for user scripts.
Usage from a script:
timer = self.entity.add_component(TimerComponent( duration=2.0, one_shot=True, autostart=True, callback=self.on_timer_done, ))
Or create and start later:
timer = self.entity.add_component(TimerComponent(duration=1.5)) timer.start()
The callback is invoked each time the timer expires. For repeating timers (
one_shot=False), it fires everydurationseconds.- property elapsed: float
- property is_finished: bool
- property is_running: bool
- property time_left: float
- class core.components.Transform(x=0.0, y=0.0, rotation=0.0, scale_x=1.0, scale_y=1.0)[source]
Bases:
Component- property position
- property rotation
- property scale_vec
- property scale_x
- property scale_y
- property x
- property y
- core.components.UIImageRenderer
alias of
ImageRenderer
- class core.components.VBoxContainerComponent(spacing=5.0)[source]
Bases:
UIComponent
- class core.components.WanderBehavior(weight: float = 1.0, circle_distance: float = 60.0, circle_radius: float = 30.0, angle_change: float = 30.0)[source]
Bases:
ComponentProduces a gentle, random meandering force.
- class core.components.WebRTCComponent(ice_servers: str = 'stun:stun.l.google.com:19302', data_channel_label: str = 'game', ordered: bool = True, max_retransmits: int = -1, autostart: bool = False, max_queue_size: int = 1024)[source]
Bases:
ComponentWebRTC component for peer-to-peer data channel communication.
Supports creating and joining peer connections with data channels for low-latency game networking. Uses aiortc under the hood. A signaling mechanism (e.g. WebSocket) is needed to exchange offers/answers/ICE candidates between peers.
- Usage in scripts:
rtc = self.entity.get_component(WebRTCComponent)
# Create an offer (caller side) rtc.create_offer()
# Poll for signaling data to send to the remote peer for sender, msg in rtc.poll():
- if sender == “local”:
# msg is a dict like {“type”: “offer”, “sdp”: “…”} or # {“type”: “candidate”, …} # Send this to the remote peer via your signaling channel ws.send_json(msg)
# On the remote side, set the remote description from received signaling rtc.set_remote_description(offer_dict) # triggers answer creation
# Feed ICE candidates from the remote peer rtc.add_ice_candidate(candidate_dict)
# Send data over the data channel rtc.send(“Hello peer!”) rtc.send_json({“action”: “move”, “x”: 10})
# Poll for incoming data channel messages for sender, msg in rtc.poll():
- if sender == “datachannel”:
print(“Received:”, msg)
# Close rtc.close()
- add_ice_candidate(candidate_dict: dict)[source]
Add an ICE candidate received from the signaling channel. candidate_dict should have keys like “candidate”, “sdpMid”, “sdpMLineIndex”.
- create_answer()[source]
Create an SDP answer (callee side). Results appear in poll() as local signaling.
- create_offer()[source]
Create an SDP offer (caller side). Results appear in poll() as local signaling.
- poll() list[tuple][source]
Drain the inbox and return a list of (sender, message) tuples. Call this in on_update.
- Sender types:
- “local”: signaling data to forward to the remote peer
(offer, answer, or ICE candidate dicts)
“datachannel”: data received from the remote peer
- “system”: connection state events like
{“event”: “connected”}, {“event”: “disconnected”}, {“event”: “error”, “message”: “…”}
- class core.components.WebSocketComponent(mode: str = 'client', host: str = 'localhost', port: int = 8765, url: str = '', autostart: bool = False, max_queue_size: int = 1024)[source]
Bases:
ComponentWebSocket component supporting both server and client modes.
- Modes:
“server”: Listens on host:port, accepts client connections.
“client”: Connects to a remote WebSocket server.
- Usage in scripts:
# Access the component ws = self.entity.get_component(WebSocketComponent)
# Start the connection (call once, e.g. in on_start) ws.start()
# In on_update, poll for incoming messages for sender, message in ws.poll():
print(f”Received: {message}”)
# Send data ws.send(“Hello”) # Client: send to server. Server: broadcast to all. ws.send_json({“key”: “val”}) # Send a JSON-serializable dict. ws.broadcast(“Hi everyone”) # Server only: broadcast to all clients. ws.send_to(client_id, “Hi”) # Server only: send to a specific client.
# Stop cleanly ws.stop()
- MODE_CLIENT = 'client'
- MODE_SERVER = 'server'
- poll() list[tuple][source]
Drain the inbox and return a list of (sender, message) tuples. Call this in on_update to process incoming messages on the game thread.
For server mode, sender is the client_id (int). For client mode, sender is “server”. Connection/disconnection events use sender “system” with message dicts like {“event”: “connected”, “client_id”: id} or {“event”: “disconnected”, “client_id”: id}.
- send(message: str)[source]
Client mode: Send a message to the server. Server mode: Broadcast a message to all connected clients.
- class core.components.WebviewComponent(url: str = '', title: str = 'Webview', width: int = 800, height: int = 600, resizable: bool = True, frameless: bool = False, autoopen: bool = False)[source]
Bases:
ComponentWebview component that opens a native browser window using pywebview.
Supports loading a URL or raw HTML content. The webview runs in a background thread so it doesn’t block the game loop. Communication between the game and webview is done via message queues.
- Usage in scripts:
wv = self.entity.get_component(WebviewComponent)
# Open a URL wv.open()
# Or open with specific URL wv.url = “https://example.com” wv.open()
# Load raw HTML wv.load_html(“<h1>Hello from engine!</h1>”)
# Evaluate JavaScript in the webview wv.evaluate_js(“document.title”)
# Poll for JS evaluation results in on_update for result in wv.poll():
print(“JS result:”, result)
# Close the webview wv.close()
- evaluate_js(script: str)[source]
Evaluate JavaScript in the webview. Results are queued and retrieved via poll().