GOKe is an ultra-lightweight, high-performance, and type-safe Entity Component System (aka ECS) for Go. It is engineered for maximum data throughput, leveraging modern Go 1.23+ Iterators and a Data-Oriented Design (DOD) architecture.
Installation • Usage • Architecture • Performance • Features • Roadmap • Benchmarks • Documentation
GOKe is primarily a high-performance ECS for game development, designed to manage massive entity counts while keeping the Go Garbage Collector (GC) completely silent. However, its core architecture a data-oriented orchestrator — makes it suitable for any scenario requiring cache-friendly iteration over millions of objects.
GOKe is the perfect companion for Ebitengine or purely server-side game loops. Managing thousands of active objects (bullets, particles, NPCs) often hits CPU bottlenecks due to pointer chasing and GC pressure. GOKe solves this via:
- Zero-Alloc Updates: Update thousands of entities in a single tick without triggering the GC.
- Decoupled Logic: Keep your rendering logic in Ebitengine and your game state in GOKe's optimized archetypes, utilizing structures like Bucket Grid.
- Deterministic Physics: Run complex collision detection systems across all entities using
RunParallel.
goke_ebiten_2048.mp4Stats: 2048 colliding AABBs | 120 TPS | 0.1-1 collisions/tick |
goke_ebiten_64.mp4Stats: 64 colliding AABBs | 120 TPS | 0.1-1 collisions/tick |
|---|---|
| Check out the full source code | |
Beyond gaming, GOKe shines in any domain where latency consistency is critical and object counts are in the millions.
-
Agent-Based Simulations: Crowd dynamics, epidemiological models, or particle physics where
$O(N)$ iteration speed is the bottleneck. - Real-time Telemetry: Processing high-frequency data streams (e.g., IoT sensor fusion) where predictable memory access patterns prevent latency spikes.
- Heavy Compute Pipelines: Logic that requires transforming large datasets every frame (e.g., 16ms window) without allocation overhead.
To ensure GOKe is the right tool for your project, consider these trade-offs:
- Small Data Sets: If you only manage a few hundred objects, a simple slice of structs will be easier to maintain and fast enough.
- Deep Hierarchies: ECS is designed for flat, high-speed iteration. If your data is naturally a deep tree (like a UI DOM), a classic tree structure might be more intuitive.
- High Structural Churn: If you are adding/removing components from thousands of entities every single frame, the overhead of archetype migration might offset the iteration gains.
GOKe requires Go 1.23 or newer.
go get github.com/kjkrol/gokeCore capabilities designed for predictable performance, cache locality, and zero-allocation cycles:
- Type-Safe Generics: Views (
NewView1[A]...NewView8) use Go generics to eliminate interface overhead, boxing, and runtime type assertions in the hot loop. - Go 1.23+ Range Iterators: Uses native
iter.Seqfor standardfor rangeloops. This allows the compiler to inline iteration logic directly, avoiding callback overhead. - Deferred Mutations: Structural changes (Create/Remove/Add components) are buffered via a Command Buffer and applied at synchronization points to ensure thread safety without heavy locking.
- Parallel Execution:
RunParalleldistributes system execution across available CPU cores with deterministic synchronization, scaling linearly with hardware resources. - Zero-Alloc Hot Loop: The architecture guarantees zero heap allocations during the update cycle (tick), preventing GC pauses during simulation.
- Entity Blueprints: Fast, template-based instantiation. Allows creating thousands of entities with identical component layouts using optimal memory copy operations.
💡 See it in action: Check the
cmddirectory for the concurrent dice game simulation demonstrating parallel systems and state management.
📘 New to ECS? Check out the Getting Started with GOKe guide for a step-by-step deep dive into building your first simulation.
package main
import (
"fmt"
"time"
"github.com/kjkrol/goke"
)
type Pos struct{ X, Y float32 }
type Vel struct{ X, Y float32 }
type Acc struct{ X, Y float32 }
func main() {
// Initialize the ECS world.
// The ECS instance acts as the central coordinator for entities and systems.
ecs := goke.New()
// Define component metadata.
// This binds Go types to internal descriptors, allowing the engine to
// pre-calculate memory layouts and manage data in contiguous arrays.
posDesc := goke.RegisterComponent[Pos](ecs)
_ = goke.RegisterComponent[Vel](ecs)
_ = goke.RegisterComponent[Acc](ecs)
// --- Type-Safe Entity Template (Blueprint) ---
// Blueprints place the entity into the correct archetype immediately and
// reserve memory for all components in a single atomic operation.
// This returns typed pointers for direct, in-place initialization.
blueprint := goke.NewBlueprint3[Pos, Vel, Acc](ecs)
// Create the entity and get direct access to its memory slots.
entity, pos, vel, acc := blueprint.Create()
*pos = Pos{X: 0, Y: 0}
*vel = Vel{X: 1, Y: 1}
*acc = Acc{X: 0.1, Y: 0.1}
// Initialize view for Pos, Vel, and Acc components
view := goke.NewView3[Pos, Vel, Acc](ecs)
// Define the movement system using the functional registration pattern
movementSystem := goke.RegisterSystemFunc(ecs, func(schedule *goke.Schedule, d time.Duration) {
// SoA (Structure of Arrays) layout ensures CPU Cache friendliness.
for head := range view.Values() {
pos, vel, acc := head.V1, head.V2, head.V3
vel.X += acc.X
vel.Y += acc.Y
pos.X += vel.X
pos.Y += vel.Y
}
})
// Configure the ECS's execution workflow and synchronization points
goke.Plan(ecs, func(ctx goke.ExecutionContext, d time.Duration) {
ctx.Run(movementSystem, d)
ctx.Sync() // Ensure all component updates are flushed and views are consistent
})
// Execute a single simulation step (standard 120 TPS)
goke.Tick(ecs, time.Second/120)
p, _ := goke.GetComponent[Pos](ecs, entity, posDesc)
fmt.Printf("Final Position: {X: %.2f, Y: %.2f}\n", p.X, p.Y)
}Check the examples/ directory for complete, ready-to-run projects.
⚠️ IMPORTANT: Setup Required: To keep the core ECS engine lightweight and free of GUI dependencies, examples are managed as isolated modules. Before running them, you must initialize the workspace:make setup
- Mini Demo – The minimalist starter.
- Simple Demo – A slightly more advanced introduction to the ECS lifecycle.
- Parallel Demo – Advanced showcase:
- Coordination of multiple systems.
- Concurrent execution using
RunParallel. - Handling structural changes via Command Buffer and explicit Sync points.
- Ebiten Demo – Graphics Integration & Spatial Physics:
- Real-time rendering using Ebitengine.
- High-performance spatial management using GOKg.
- Custom physics pipeline: Velocity Inversion is processed strictly before Position Compensation to ensure boundary stability.
- Note: Run
makeinside the example directory to fetch dependencies and start the demo.
GOKe is an archetype-based ECS designed for deterministic performance. It shifts structural overhead (like offset calculations) to the initialization phase and uses a chunked SoA layout to maintain consistent throughput regardless of scale.
The storage layer is engineered to maximize cache hits and eliminate allocation spikes ("GC jitter").
- Chunked SoA (Structure of Arrays): Instead of monolithic slices that require costly resizing (copying millions of elements) when capacity is exceeded, GOKe manages data in fixed-size Memory Pages (aligned to L1 Cache, e.g., 96KB).
- Stable Growth: Memory allocation is linear and "stepless". Adding the 1,000,001st entity simply allocates one small memory chunk, avoiding the massive latency spike of doubling a large array.
- Cache Locality: Inside each chunk, components are packed in a tight SoA layout (
[IDs...][CompA...][CompB...]), ensuring high-efficiency hardware prefetching.
- Generation-based Recycling: Entities are tracked via 64-bit IDs (32-bit Index / 32-bit Generation). This prevents entity aliasing—stale references to destroyed entities are instantly recognized as invalid when their memory slot is reused.
- Archetype Masks: Supports rapid composition checks using fast, constant-time bitwise operations. This allows for complex queries over component types without iterating over unrelated data.
GOKe bypasses traditional bottlenecks like reflection and map lookups in the execution phase.
- Flat Cache View: Views pre-calculate direct pointers to component columns within active chunks. This eliminates map lookups and pointer chasing inside the hot loop.
-
Zero-Overhead Iteration: Powered by native
for rangeover functions (iter.Seq), allowing the Go compiler to perform aggressive loop inlining directly over the memory pages. -
Deterministic
$O(1)$ Filter: Querying specific entities via the Centralized Record System takes constant time regardless of the total entity count ($N$ ) by mapping IDs directly to(ChunkIndex, RowIndex)coordinates. - Hardware Prefetching Optimization: View structures are optimized to keep the prefetcher strictly focused on the data stream, minimizing cache pollution during iteration.
- Deferred Commands: State consistency is maintained via
Commands. Structural changes (add/remove) are buffered and applied during explicitSync()points to ensure memory safety and cache integrity. - Thread-Safe Concurrency: Native support for
RunParallelexecution. GOKe provides the infrastructure for multi-core scaling, assuming the developer ensures disjoint component sets to avoid race conditions.
The engine is engineered for extreme scalability and deterministic performance. By utilizing a Centralized Record System (dense array lookup) instead of traditional hash maps, we have effectively decoupled both structural changes and query performance from the total entity count (
$N$ ).
GOKe delivers near-metal speeds by eliminating heap allocations and leveraging L1/L2 cache locality.
| Category | Operation | Performance (1k Baseline) | Allocs | Technical Mechanism |
|---|---|---|---|---|
| Throughput | Iteration | 0.36 – 0.66 ns/ent | 0 | Linear SoA (1-8 components) |
| Scalability | 1.39 – 5.38 ns/ent | 0 | Centralized Record Lookup | |
| Structural | Create Entity | 21.31 - 26.84 ns/op | 0 | Blueprint-based (1-4 comps) |
| Structural | Migrate Component | 37.36 ns/op | 0 | Archetype Move (Insert) |
| Structural | Remove Entity | 17.95 ns/op | 0 | Index Recycling |
| Access | Get Component | 4.49 ns/op | 0 | Direct Generation Check |
📊 Deep Dive: For a full breakdown of hardware specs, stress tests, and
$O(N)$ vs$O(1)$ scaling charts, see BENCHMARKS.md.
Run the suite on your own hardware:
go test -bench=. ./... -benchmemCurrent development focus and planned improvements:
- Batch Operations: High-performance bulk operations for entity creation/destruction to maximize overhead reduction during large-scale processing.
- Ebitengine Integration: Dedicated helpers for seamless state synchronization between GOKe systems and Ebitengine's loop.
🛠️ Live Feature Tracker We manage our long-term goals through GitHub Issues. View all planned core engine expansions and functional capabilities here: Explore all Pending Features ↗
GOKe is licensed under the MIT License. See the LICENSE file for more details.
- API Reference: Detailed documentation and examples are available on pkg.go.dev.
- Wiki & Guides: For a step-by-step deep dive into building your first simulation, check the Getting Started with GOKe guide.
- Internal Mechanics: For a technical breakdown of the engine's core, check the
doc.gofiles within theecspackages.