SwiftrixCore is a small, focused game engine written in Swift 5.9.
It provides a clear, component-based model for building interactive 2D worlds
without tying you to any specific rendering, input, or audio framework.
- Scene graph with hierarchical game objects
- Component-based design (scripts, views, colliders, controls)
- Deterministic game loop with fixed-step physics
- Event bus for decoupled gameplay logic
- Pluggable input and physics via protocols
- Introspection utilities for debugging and tools
The engine is intended for rapid prototyping, small-to-medium games, and AI-assisted workflows where clarity and testability matter more than features.
SwiftrixCore is a Swift Package Manager (SwiftPM) library. The repository also ships an optional SpriteKit adapter module for Apple-platform hosts.
- Swift 5.9+
- macOS 13+ or iOS 16+ (per
Package.swift)
Add SwiftrixCore to your Package.swift either via a local path or your Git
remote:
// Example Package.swift snippet
dependencies: [
// Using your own remote URL or fork:
.package(url: "https://github.com/<your-account>/Swiftrix.git", branch: "main"),
// or, if you keep Swiftrix as a local package:
// .package(path: "../Swiftrix"),
],
targets: [
.target(
name: "YourGame",
dependencies: [
.product(name: "SwiftrixCore", package: "Swiftrix")
]
)
]Adjust the package name, URL, and path to match how you host this repository.
Scene represents a world containing a tree of game objects and coordinating
systems such as input, physics, and events.
The engine provides an open Scene class, which wires together:
EventBus(default:DefaultEventBus)InputSystem(default:DefaultInputSystemor a host-provided implementation)PhysicsWorld(default:DefaultPhysicsWorld)
GameObject is a node in the scene graph:
- has a name and unique identifier
- holds a
Transform2Dfor position/rotation/scale - can have children
- can own multiple components
The standard concrete implementation is GameObject.
Components attach behaviour and data to game objects. Key component classes:
Component— base class for attachable behaviorsScript— custom gameplay logic (movement, AI, reactions)View— rendering-related state (to be interpreted by your host)Collider— 2D collision shapes used byPhysicsWorldControlComponent— maps high-level input to gameplay responses
Script subclasses can access their gameObject’s hierarchy and transforms via
bridged properties: parent, children, localTransform/globalTransform,
position, rotation, scale, globalPosition,
globalRotation, globalScale, plus component helpers
getComponent(_:) / getComponents(_:).
GameLoop drives a Scene using a fixed timestep for deterministic systems
and a variable update for scripts:
fixedUpdate(fixedDeltaTime:)for physics and other deterministic systemsupdate(deltaTime:)for scripts and general logicdraw()for rendering hooks
You can embed GameLoop into your host application (e.g. SpriteKit or a custom
rendering layer) and decide how often to call tick(deltaTime:).
GameEventandEventBus(DefaultEventBus) provide a simple event pipeline for decoupled communication.InputSystemis an abstraction for logical input state; hosts implement it to translate platform-specific input into engine-level axes and actions.
The following minimal example shows how to create a scene, add a game object
with a custom script, and drive it with GameLoop. You can run a variant of
this from your own app target or test target.
import SwiftrixCore
// 1. Define a simple script
final class MoveRightScript: Script {
override func update(deltaTime: TimeInterval) {
guard let gameObject else { return }
var transform = gameObject.localTransform
transform.position.x += 1.0 * deltaTime
gameObject.localTransform = transform
}
}
// 2. Bootstrap scene and loop
let scene = Scene()
let root = GameObject(name: "Player")
root.addComponent(MoveRightScript())
scene.addRootObject(root)
let loop = GameLoop(scene: scene)
// 3. Step the loop from your host (e.g. 60 FPS)
loop.tick(deltaTime: 1.0 / 60.0)In a real application, you would:
- integrate a rendering backend (e.g. SpriteKit) and interpret
Viewcomponents for drawing, - implement or wrap an
InputSystemto feed input into your scene, - call
tick(deltaTime:)from your platform’s frame/update callback.
The engine core stays independent of SpriteKit; you integrate it from a host
app target. The snippet below shows one way to drive GameLoop from an
SKScene:
import SpriteKit
import SwiftrixCore
final class GameScene: SKScene {
private var swiftrixScene: Scene!
private var loop: GameLoop!
private var lastUpdateTime: TimeInterval = 0
override func didMove(to view: SKView) {
let input = DefaultInputSystem()
swiftrixScene = Scene(inputSystem: input)
loop = GameLoop(scene: swiftrixScene)
let player = GameObject(name: "Player")
// Attach components (Script, View, Collider, etc.)
swiftrixScene.addRootObject(player)
}
override func update(_ currentTime: TimeInterval) {
let deltaTime = lastUpdateTime == 0 ? 0 : currentTime - lastUpdateTime
lastUpdateTime = currentTime
loop.tick(deltaTime: deltaTime)
renderSwiftrixObjects()
}
private func renderSwiftrixObjects() {
// Traverse swiftrixScene.rootObjects and map View components to SKNodes.
// This is where you keep SpriteKit concerns, outside SwiftrixCore.
}
}In this setup:
SwiftrixCoreowns game state, logic, and physics.- The SpriteKit scene owns drawing and platform-level input.
- Communication between the two flows through components (
View,ControlComponent) and systems (InputSystem,EventBus).
For hosts that want a more turnkey integration on Apple platforms, this repository includes a separate SwiftPM target:
SwiftrixSpriteKitRendering— a SpriteKit-backedSpriteKitScenethat:- mirrors the core game object hierarchy into an
SKScene - drives the core
GameLoopfrom a display-linked clock - exposes lifecycle controls (start/pause/resume/stop/reset)
- provides debug overlays, camera helpers, and basic hit-testing
- mirrors the core game object hierarchy into an
Minimal setup in a host app:
import SwiftrixCore
import SwiftrixSpriteKitRendering
import SpriteKit
final class GameScene: SpriteKitScene {
override func bootstrapScene() {
let player = GameObject(name: "Player")
player.addComponent(SpriteView(textureName: "player", size: CGSize(width: 24, height: 24)))
coreScene.addRootObject(player)
}
}
let spriteKitScene = GameScene()
let skView = SKView(frame: UIScreen.main.bounds)
skView.presentScene(spriteKitScene)
spriteKitScene.start()For more details (performance budgets, overlays, camera follow, hit-testing),
see specs/001-spritekit-renderer/quickstart.md.
Relevant directories in this repository:
Sources/SwiftrixCore— engine core (scenes, game objects, components, events, physics, input, loop, introspection)Sources/SwiftrixSpriteKitRendering— SpriteKit adapter module (host-side)Tests/SwiftrixCoreTests— XCTest-based test suite for the engine coreTests/SwiftrixSpriteKitRenderingTests— tests for the SpriteKit adapterspecs/000-swiftrix-engine-core— high-level specification and design docs for the corespecs/001-spritekit-renderer— spec/plan/quickstart for the SpriteKit adapter
Additional documentation:
docs/engine-concepts.md— overview of core engine concepts and patterns.docs/game-development-guidelines.md— recommended patterns for structuring Swiftrix-based game code.docs/host-integration-spritekit.md— detailed host integration examples with SpriteKit.docs/debugging-and-introspection.md— practical tips for debugging and inspecting Swiftrix scenes and adapter state.docs/unit-test-coverage.md— unit-test coverage plan and edge-case checklist (contributors).
For more detailed architecture notes, see:
specs/000-swiftrix-engine-core/spec.mdspecs/000-swiftrix-engine-core/plan.mdspecs/000-swiftrix-engine-core/tasks.md
- Start here: this
README.md(installation, concepts, quickstart). - Documentation index:
docs/index.md(where to start + how to generate API docs). - Single-file API reference (Markdown):
docs/api-reference.md(AI-friendly). - Public API tour:
docs/public-api.md(walkthrough of exported types). - Learn the model:
docs/engine-concepts.md. - Build a game on top:
docs/game-development-guidelines.md. - Integrate with SpriteKit:
docs/host-integration-spritekit.md. - Debug and inspect scenes/adapter state:
docs/debugging-and-introspection.md. - Use the adapter’s feature quickstart:
specs/001-spritekit-renderer/quickstart.md.
- Contribution workflow and constraints:
CONTRIBUTING.md— overview of expectations and entry points.AGENTS.md— detailed guidelines for humans and AI agents.
- Testing strategy:
docs/unit-test-coverage.md
- Core engine design:
specs/000-swiftrix-engine-core/spec.mdspecs/000-swiftrix-engine-core/plan.mdspecs/000-swiftrix-engine-core/tasks.md
- SpriteKit adapter design:
specs/001-spritekit-renderer/spec.mdspecs/001-spritekit-renderer/plan.mdspecs/001-spritekit-renderer/tasks.md
These “maintainer” docs are authoritative for architecture and API changes; user docs should stay aligned with them.
From the repository root:
swift testTests cover core behaviors such as:
- scene traversal and game loop integration
- component lifecycle and game object hierarchy
- physics world registration and collision events
- input system behavior and event dispatch
When making changes to SwiftrixCore, prefer to add or extend tests in
Tests/SwiftrixCoreTests to keep coverage high.
SwiftrixCore focuses on:
- clear, predictable behavior
- small, composable components
- engine core decoupled from any specific rendering or input framework
- being friendly to debugging, tooling, and AI agents
It deliberately does not include:
- built-in rendering, audio, or asset loading
- a scene editor or inspector UI
- networking or persistence
Those responsibilities belong to host applications and tooling built on top of the engine.
MIT © Yauheni Lychkouski