This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
GECS is a lightweight, performant Entity Component System (ECS) framework for Godot 4.x that integrates seamlessly with Godot's node system. The framework provides a query-based entity filtering system with optimized component indexing.
The framework is built around five main classes:
- Entity (
addons/gecs/entity.gd): Container nodes that hold components and relationships. Entities extend Godot's Node class and can be placed in the scene tree. - Component (
addons/gecs/component.gd): Data-only resources that extend Godot's Resource class. Components hold properties but no logic. - System (
addons/gecs/system.gd): Processing nodes that operate on entities with specific components. Systems contain the game logic. - World (
addons/gecs/world.gd): Manager for all entities and systems, handles querying and processing. - ECS Singleton (
addons/gecs/ecs.gd): Global access point for the current World instance.
The QueryBuilder (addons/gecs/query_builder.gd) provides powerful entity filtering:
with_all([Components])- Entities must have all specified componentswith_any([Components])- Entities must have at least one componentwith_none([Components])- Entities must not have these componentswith_relationship([Relations])- Entities must have these relationshipswith_group("group_name")- Filter by Godot groups
Systems are organized by groups and processed via:
# Process specific system group
ECS.process(delta, "physics")
# Process all systems
ECS.process(delta)The project uses gdUnit4 for testing. Tests are located in addons/gecs/tests/.
No test should be created anywhere else other than addons/gecs/tests/
Windows:
# Set environment variable (one-time setup)
setx GODOT_BIN "D:\path\to\Godot.exe"
# Enable colored console output (one-time setup)
REG ADD HKCU\CONSOLE /f /v VirtualTerminalLevel /t REG_DWORD /d 1Mac/Linux:
# Set environment variable (add to ~/.bashrc or ~/.zshrc)
export GODOT_BIN="/Applications/Godot.app/Contents/MacOS/Godot"
# Make script executable
chmod +x ./addons/gdUnit4/runtest.shIMPORTANT: Always use res:// prefix for file paths!
# Windows
addons/gdUnit4/runtest.cmd -a "res://addons/gecs/tests"
addons/gdUnit4/runtest.cmd -a "res://addons/gecs/tests/core/test_world.gd"
addons/gdUnit4/runtest.cmd -a "res://addons/gecs/tests" -c
# Linux/Mac
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests"
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/core/test_world.gd"
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests" -c# Run specific test file (use res:// prefix!)
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/core/test_entity.gd"
# Run specific test method with :: syntax (NO SPACES)
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/core/test_entity.gd::test_add_and_get_component"
# Run multiple test directories
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/core" -a "res://addons/gecs/tests/performance"
# Ignore specific tests (opposite selection)
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/performance" -i "TestEntityPerf:test_entity_creation"
# Continue on failures (don't fail fast)
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests" -c
# Use specific test configuration
addons/gdUnit4/runtest.sh -conf GdUnitRunner.cfg-a, --add: Add test suite/directory to execution (REQUIRED)-i, --ignore: Ignore specific test suite or test case-c, --continue: Continue on test failures (don't fail fast)-conf, --config: Run tests from specific config file--help: Show all available commands--help-advanced: Show advanced options
GdUnit4 supports parameterized tests to run the same test with different inputs:
# Example: test with multiple scales
func test_entity_creation(scale: int, test_parameters := [[100], [1000], [10000]]):
var entities = []
for i in scale:
entities.append(Entity.new())
# Test will run 3 times with scale = 100, 1000, 10000- Always use
res://prefix for file paths - No spaces around
::when running specific test methods - Path format matters: Windows uses backslashes in regular paths but forward slashes with
res:// - Test names are case-sensitive
- Make sure GODOT_BIN is set before running tests
Simple performance tests that record timing data to JSONL files for easy graphing:
# Run all performance tests
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/performance"
# Run specific performance category
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/performance/test_entity_perf.gd"
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/performance/test_component_perf.gd"
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/performance/test_query_perf.gd"
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/performance/test_system_perf.gd"
# Run specific test with specific scale
addons/gdUnit4/runtest.sh -a "res://addons/gecs/tests/performance/test_entity_perf.gd::test_entity_creation"Performance Results:
- Each test writes to
reports/perf/{test_name}.jsonl - One JSON per line format for easy parsing
- Track performance over time by test name and scale
- Example:
reports/perf/entity_creation.jsonl
{"timestamp":"2025-01-13T10:23:45","test":"entity_creation","scale":100,"time_ms":12.5,"godot_version":"4.5"}
{"timestamp":"2025-01-13T11:30:12","test":"entity_creation","scale":100,"time_ms":11.8,"godot_version":"4.5"}Using Parameterized Tests: Performance tests use GdUnit4's parameterized test feature to automatically run tests at different scales (100, 1000, 10000 entities). Each scale generates a separate result entry.
GECS uses an automated release workflow that creates clean distribution branches for different use cases.
To create a new release:
-
Tag the release (use semantic versioning):
git tag v1.0.0 git push origin v1.0.0
-
The GitHub workflow automatically creates two branches:
release-v1.0.0- For submodule users (addon contents at root level)godot-asset-library-v1.0.0- For Godot Asset Library submissions (properaddons/gecs/structure)
Both branches contain:
- Clean addon code (no test directories)
- README.md and LICENSE files
- Production-ready GECS framework
For users:
# Submodule installation
git submodule add -b release-v1.0.0 https://github.com/your-repo/gecs.git gecs
# Asset Library - submit the godot-asset-library-v1.0.0 branchVersion numbering: Use semantic versioning (v1.0.0, v1.1.0, v2.0.0, etc.)
Component Creation:
class_name C_MyComponent
extends Component
@export var my_property: float = 0.0Entity Creation:
class_name MyEntity
extends Entity
func define_components() -> Array:
return [C_Transform.new(), C_Velocity.new()]System Creation:
class_name MySystem
extends System
func query():
return q.with_all([C_Transform, C_Velocity])
func process(entity: Entity, delta: float):
# Process each matching entityThe project provides script templates in script_templates/Node/ for:
component.gd- Component templateentity.gd- Entity templatesystem.gd- System templateobserver.gd- Observer (reactive system) template
addons/gecs/world.gd- Core world management and entity indexingaddons/gecs/query_builder.gd- Query system implementationaddons/gecs/relationship.gd- Entity relationship systemaddons/gecs/observer.gd- Reactive systems for component changes
GECS supports entity relationships for hierarchical queries with two matching modes:
# Add relationship
entity.add_relationship(Relationship.new(C_ChildOf.new(), parent_entity))
# Query by type (matches any component of this type)
q.with_relationship([Relationship.new(C_ChildOf.new(), parent_entity)])
# Check relationships by type
entity.has_relationship(Relationship.new(C_Damage.new(), target))# Query relationships by property criteria
var high_damage = q.with_relationship([
Relationship.new({C_Damage: {'amount': {"_gte": 50}}}, target)
]).execute()
# Query both relation AND target properties
var strong_buffs = q.with_relationship([
Relationship.new(
{C_Buff: {'duration': {"_gt": 10}}},
{C_Player: {'level': {"_gte": 5}}}
)
]).execute()# Remove specific number of relationships
entity.remove_relationship(Relationship.new(C_Damage.new(), null), 1) # Remove 1 damage
entity.remove_relationship(Relationship.new(C_Buff.new(), null), 3) # Remove up to 3 buffs
entity.remove_relationship(Relationship.new(C_Effect.new(), null)) # Remove all effects (default)
# Remove with component queries
entity.remove_relationship(
Relationship.new({C_Damage: {'amount': {"_gt": 20}}}, null),
2 # Remove up to 2 high-damage effects
)- Components are data-only containers with @export properties
- Systems contain all game logic and process entities by component queries
- Entities are automatically indexed by components for efficient querying
- Use
ECS.world.queryto build and execute entity queries - Systems can be grouped and processed at different intervals (physics vs render)
This is a Godot 4.x project with the following key settings:
- ECS Singleton: Auto-loaded at
res://addons/gecs/ecs.gd - Debug Logging:
gecs.log_level=4in project settings - Enabled Plugins: GECS (
res://addons/gecs/plugin.cfg) and gdUnit4 (res://addons/gdUnit4/plugin.cfg)
The GECS framework architecture is built around these key files:
addons/gecs/world.gd- Core world management with component indexing and query cachingaddons/gecs/query_builder.gd- Optimized entity filtering with performance optimizationsaddons/gecs/relationship.gd- Entity relationship system for hierarchical queriesaddons/gecs/observer.gd- Reactive systems for component changesaddons/gecs/array_extensions.gd- Optimized set operations for queries