{"id":50682273,"url":"https://github.com/yohamta0/donburi-ecs","last_synced_at":"2026-06-25T18:00:56.256Z","repository":{"id":38460961,"uuid":"450453231","full_name":"yohamta0/donburi-ecs","owner":"yohamta0","description":"Just another ECS library for Go/Ebitengine","archived":false,"fork":false,"pushed_at":"2026-05-17T11:41:48.000Z","size":2026,"stargazers_count":372,"open_issues_count":8,"forks_count":30,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-06-09T21:06:29.512Z","etag":null,"topics":["ebitengine","ecs","entity-component-system","game-engine","gamedev"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/yohamta/donburi","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yohamta0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-01-21T10:46:25.000Z","updated_at":"2026-06-04T15:50:44.000Z","dependencies_parsed_at":"2024-03-11T03:25:39.267Z","dependency_job_id":"8f117292-88f9-4c19-87ce-d9e92e757567","html_url":"https://github.com/yohamta0/donburi-ecs","commit_stats":{"total_commits":231,"total_committers":16,"mean_commits":14.4375,"dds":"0.11688311688311692","last_synced_commit":"3f0ecd6093234c6e3a3941524e04f7abd28970ff"},"previous_names":["yottahmd/donburi","yohamta/donburi","yohamta0/donburi-ecs"],"tags_count":65,"template":false,"template_full_name":null,"purl":"pkg:github/yohamta0/donburi-ecs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yohamta0%2Fdonburi-ecs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yohamta0%2Fdonburi-ecs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yohamta0%2Fdonburi-ecs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yohamta0%2Fdonburi-ecs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yohamta0","download_url":"https://codeload.github.com/yohamta0/donburi-ecs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yohamta0%2Fdonburi-ecs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34786231,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-25T02:00:05.521Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ebitengine","ecs","entity-component-system","game-engine","gamedev"],"created_at":"2026-06-08T20:00:23.304Z","updated_at":"2026-06-25T18:00:56.222Z","avatar_url":"https://github.com/yohamta0.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"\u003cimg align=\"right\" width=\"150\" src=\"https://user-images.githubusercontent.com/1475839/150521755-977f545b-4436-4059-87ac-1129541ad236.png\" alt=\"donburi\" title=\"donburi\" /\u003e \u003ch1\u003eDonburi\u003c/h1\u003e\n\n\u003cimg src=\"https://github.com/yohamta/donburi/actions/workflows/test.yaml/badge.svg\" /\u003e [![Go Reference](https://pkg.go.dev/badge/github.com/yohamta/donburi.svg)](https://pkg.go.dev/github.com/yohamta/donburi)\n\nDonburi is an Entity Component System library for Go / Ebitengine inspired by [legion](https://github.com/amethyst/legion).\n\nIt aims to be a feature rich and high-performance [ECS](https://en.wikipedia.org/wiki/Entity_component_system) Library.\n\n## Contents\n\n- [Contents](#contents)\n- [Summary](#summary)\n- [Examples](#examples)\n- [Installation](#installation)\n- [Getting Started](#getting-started)\n  - [Worlds](#worlds)\n  - [Queries](#queries)\n- [Ordered Queries](#ordered-queries)\n  - [Tags](#tags)\n  - [Systems (Experimental)](#systems-experimental)\n  - [Debug](#debug)\n- [Features](#features)\n  - [Math](#math)\n  - [Transform](#transform)\n  - [Events](#events)\n- [Projects Using Donburi](#projects-using-donburi)\n  - [Games](#games)\n  - [Libraries](#libraries)\n- [Architecture](#architecture)\n- [How to contribute?](#how-to-contribute)\n- [Contributors](#contributors)\n\n## Summary\n\n- It introduces the concept of [Archetype](https://docs.unity3d.com/Packages/com.unity.entities@0.2/manual/ecs_core.html), which allows us to query entities very efficiently based on the components layout.\n- It is possible to combine `And`, `Or`, and `Not` conditions to perform complex queries for components.\n- It avoids reflection for performance.\n- Ability to dynamically add or remove components from an entity.\n- Type-safe APIs powered by Generics\n- Zero dependencies\n- Provides [Features](#features) that are common in game dev (e.g., `math`, `transform`, `hieralchy`, `events`, etc) built on top of the ECS architecture.\n\n## Examples\n\nTo check all examples, visit [this](https://github.com/yohamta/donburi/tree/main/examples) page.\n\nThe bunnymark example was adapted from [mizu](https://github.com/sedyh/mizu)'s code, which is made by [sedyh](https://github.com/sedyh). \n\n\u003ca href=\"https://github.com/yohamta/donburi/tree/main/examples/bunnymark\"\u003e \u003cimg width=\"200\" src=\"https://user-images.githubusercontent.com/1475839/150521292-9d3ec2c9-b96f-4cc1-a778-57dabfbd46b6.gif\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/yohamta/donburi/tree/main/examples/platformer\"\u003e \u003cimg width=\"200\" src=\"./examples/platformer/assets/images/example.gif\"\u003e\u003c/a\u003e \n\n## Installation\n\n```\ngo get github.com/yohamta/donburi\n```\n\n## Getting Started\n\n### Worlds\n\n```go\nimport \"github.com/yohamta/donburi\"\n\nworld := donburi.NewWorld()\n```\n\nEntities can be created via either `Create` (for a single entity) or `CreateMany` (for a collection of entities with the same component types). The world will create a unique ID for each entity upon insertion that we can use to refer to that entity later.\n\n```go\n// Component is any struct that holds some kind of data.\ntype PositionData struct {\n  X, Y float64\n}\n\ntype VelocityData struct {\n  X, Y float64\n}\n\n// ComponentType represents kind of component which is used to create or query entities.\nvar Position = donburi.NewComponentType[PositionData]()\nvar Velocity = donburi.NewComponentType[VelocityData]()\n\n// Create an entity by specifying components that the entity will have.\n// Component data will be initialized by default value of the struct.\nentity = world.Create(Position, Velocity)\n\n// We can use entity (it's a wrapper of int64) to get an Entry object from World\n// which allows you to access the components that belong to the entity.\nentry := world.Entry(entity)\n\n// You can set or get the data via the ComponentType\nPosition.SetValue(entry, math.Vec2{X: 10, Y: 20})\nVelocity.SetValue(entry, math.Vec2{X: 1, Y: 2})\n\nposition := Position.Get(entry)\nvelocity := Velocity.Get(entry)\n\nposition.X += velocity.X\nposition.Y += velocity.y\n```\n\nComponents can be added and removed through `Entry` objects.\n\n```go\n// Fetch the first entity with PlayerTag component\nquery := donburi.NewQuery(filter.Contains(PlayerTag))\n// Query.First() returns only the first entity that \n// matches the query.\nif entry, ok := query.First(world); ok {\n  donburi.Add(entry, Position, \u0026PositionData{\n    X: 100,\n    Y: 100,\n  })\n  donburi.Remove(entry, Velocity)\n}\n```\n\nEntities can be removed from World with the World.Remove() as follows:\n\n```go\nif SomeLogic.IsDead(world, someEntity) {\n  // World.Remove() removes the entity from the world.\n  world.Remove(someEntity)\n  // Deleted entities become invalid immediately.\n  if world.Valid(someEntity) == false {\n    println(\"this entity is invalid\")\n  }\n}\n```\n\nEntities can be retrieved using the `First` and `Iter` methods of Components as follows:\n\n```go\n// GameState Component\ntype GameStateData struct {\n  // .. some data\n}\nvar GameState = donburi.NewComponentType[GameStateData]()\n\n// Bullet Component\ntype BulletData struct {\n  // .. some data\n}\nvar Bullet = donburi.NewComponentType[BulletData]()\n\n// Init the world and create entities\nworld := donburi.NewWorld()\nworld.Create(GameState)\nworld.CreateMany(100, Bullet)\n\n// Query the first GameState entity\nif entry, ok := GameState.First(world); ok {\n  gameState := GameState.Get(entry)\n  // .. do stuff with the gameState entity\n}\n\n// Query all Bullet entities\nfor entry := range Bullet.Iter(world) {\n  bullet := Bullet.Get(entry)\n  // .. do stuff with the bullet entity\n}\n```\n\n### Queries\n\nQueries allow for high performance and expressive iteration through the entities in a world, to get component references, test if an entity has a component or to add and remove components.\n\n```go\n// Define a query by declaring what componet you want to find.\nquery := donburi.NewQuery(filter.Contains(Position, Velocity))\n\n// Iterate through the entities found in the world\nfor entry := range query.Iter(world) {\n  // An entry is an accessor to entity and its components.\n  position := Position.Get(entry)\n  velocity := Velocity.Get(entry)\n  \n  position.X += velocity.X\n  position.Y += velocity.Y\n}\n```\n\nThere are other types of filters such as `And`, `Or`, `Exact` and `Not`. Filters can be combined wth to find the target entities.\n\nFor example:\n\n```go\n// This query retrieves entities that have an NpcTag and no Position component.\nquery := donburi.NewQuery(filter.And(\n  filter.Contains(NpcTag),\n  filter.Not(filter.Contains(Position))))\n```\n\nIf you need to determine if an entity has a component, there is `entry.HasComponent`\n\nFor example:\n\n```go\n// We have a query for all entities that have Position and Size, but also any of Sprite, Text or Shape.\nquery := donburi.NewQuery(\n  filter.And(\n    filter.Contains(Position, Size),\n    filter.Or(\n      filter.Contains(Sprite),\n      filter.Contains(Text),\n      filter.Contains(Shape),\n    ),\n  ),\n)\n\n// In our query we can check if the entity has some of the optional components before attempting to retrieve them\nfor entry := range query.Iter(world) {\n  // We'll always be able to access Position and Size\n  position := Position.Get(entry)\n  size := Size.Get(entry)\n  \n  if entry.HasComponent(Sprite) {\n    sprite := Sprite.Get(entry)\n    // .. do sprite things\n  }\n  \n  if entry.HasComponent(Text) {\n    text := Text.Get(entry)\n    // .. do text things\n  }\n  \n  if entry.HasComponent(Shape) {\n    shape := Shape.Get(entry)\n    // .. do shape things\n  }\n}\n```\n\n## Ordered Queries\nSometimes you may need to iterate a query in a specific order. Donburi supports this through the `OrderedQuery[T]` type.\nIn order to use this, the component must implement the IOrderable interface:\n```go\ntype IOrderable interface {\n\tOrder() int\n}\n```\n\nExample:\nHere we assume the `spatial.TransformComponent` implements `Order()`.\n```go\nq := donburi.NewOrderedQuery[spatial.Transform](\nfilter.Contains(sprite.Component, spatial.TransformComponent))\n\nfor entry := range q.IterOrdered(w) {\n  // This will be iterated according to the spatial.TransformComponent's Order() function.\n}\n```\n\n### Tags\n\nOne or multiple \"Tag\" components can be attached to an entity. \"Tag\"s are just components with a single name string as data.\n\nHere is the utility function to create a tag component.\n\n```go\n// This is the utility function to make tag component\nfunc NewTag(name string) *ComponentType {\n  return NewComponentType(Tag(name))\n}\n```\nSince \"Tags\" are components, they can be used in queries in the same way as components as follows:\n\n```go\nvar EnemyTag = donburi.NewTag(\"Enemy\")\nworld.CreateMany(100, EnemyTag, Position, Velocity)\n\n// Search entities with EnemyTag\nfor entry := range EnemyTag.Iter(world) {\n  // Perform some operation on the Entities with the EnemyTag component.\n}\n```\n\n### Systems (Experimental)\n\n**⚠ this feature is currently experimental, the API can be changed in the future.**\n\nThe [ECS package](https://github.com/yohamta/donburi/tree/main/ecs) provides so-called **System** feature in ECS which can be used together with a `World` instance.\n\nSee the [GoDoc](https://pkg.go.dev/github.com/yohamta/donburi/ecs) and [Example](https://github.com/yohamta/donburi/tree/main/examples/bunnymark_ecs).\n\nHow to create an ECS instance:\n\n```go\nimport (\n  \"github.com/yohamta/donburi\"\n  ecslib \"github.com/yohamta/donburi/ecs\"\n)\n\nworld := donburi.NewWorld()\necs := ecslib.NewECS(world)\n```\n\nA `System` is created from just a function that receives an argument `(ecs *ecs.ECS)`.\n\n```go\n// Some System's function\nfunc SomeFunction(ecs *ecs.ECS) {\n  // ...\n}\n\necs.AddSystem(SomeFunction)\n```\n\nWe can provide `Renderer` for certain system.\n\n```go\necs.AddRenderer(ecs.LayerDefault, DrawBackground)\n\n// Draw all systems\necs.Draw(screen)\n```\n\nThe `Layer` parameter allows us to control the order of rendering systems and to which screen to render. A `Layer` is just an `int` value. The default value is just `0`.\n\nFor example:\n```go\n\nconst (\n  LayerBackground ecslib.LayerID = iota\n  LayerActors\n)\n\n// ...\n\necs.\n  AddSystem(UpdateBackground).\n  AddSystem(UpdateActors).\n  AddRenderer(LayerBackground, DrawBackground).\n  AddRenderer(LayerActors, DrawActors)\n\n// ...\n\nfunc (g *Game) Draw(screen *ebiten.Image) {\n  screen.Clear()\n  g.ecs.DrawLayer(LayerBackground, screen)\n  g.ecs.DrawLayer(LayerActors, screen)\n}\n```\n\nThe `ecs.Create()` and `ecs.NewQuery()` wrapper-functions allow to create and query entities on a certain `Layer`:\n\nFor example:\n```go\nvar layer0 ecs.LayerID = 0\n\n// Create an entity on layer0\necslib.Create(layer0, someComponents...)\n\n// Create a query to iterate entities on layer0\nqueryForLayer0 := ecslib.NewQuery(layer0, filter.Contains(someComponent))\n```\n\n### Debug\n\nThe [debug package](https://pkg.go.dev/github.com/yohamta/donburi/features/debug) provides some debug utilities for `World`.\n\nFor example:\n```go\ndebug.PrintEntityCounts(world)\n\n// [Example Output]\n// Entity Counts:\n// Archetype Layout: {TransformData, Size, SpriteData, EffectData } has 61 entities\n// Archetype Layout: {TransformData, Size, SpriteData, ColliderData } has 59 entities\n// Archetype Layout: {TransformData, Size, SpriteData, WeaponData} has 49 entities\n// ...\n```\n\n## Features\n\nUnder the [features](https://github.com/yohamta/donburi/tree/main/features) directory, we develop common functions for game dev. Any kind of [Issues](https://github.com/yohamta/donburi/issues) or [PRs](https://github.com/yohamta/donburi/pulls) will be very appreciated.\n\n### Math\n\nThe [math package](https://github.com/yohamta/donburi/tree/main/features/math) provides the basic types (Vec2 etc) and helpers.\n\nSee the [GoDoc](https://pkg.go.dev/github.com/yohamta/donburi/features/math) for more details.\n\n### Transform\n\nThe [transform package](https://github.com/yohamta/donburi/tree/main/features/transform) provides the `Tranform` Component and helpers.\n\nIt allows us to handle `position`, `rotation`, `scale` data relative to the parent.\n\nThis package was adapted from [ariplane](https://github.com/m110/airplanes)'s code, which is created by [m110](https://github.com/m110). \n\nFor example:\n```go\nw := donburi.NewWorld()\n\n// setup parent\nparent := w.Entry(w.Create(transform.Transform))\n\n// set world position and scale for the parent\ntransform.SetWorldPosition(parent, dmath.Vec2{X: 1, Y: 2})\ntransform.SetWorldScale(parent, dmath.Vec2{X: 2, Y: 3})\n\n// setup child\nchild := w.Entry(w.Create(transform.Transform))\ntransform.Transform.SetValue(child, transform.TransformData{\n  LocalPosition: dmath.Vec2{X: 1, Y: 2},\n  LocalRotation: 90,\n  LocalScale:    dmath.Vec2{X: 2, Y: 3},\n})\n\n// add the child to the parent\ntransform.AppendChild(parent, child, false)\n\n// get world position of the child with parent's position taken into account\npos := transform.WorldPosition(child)\n\n// roatation\nrot := transform.WorldRotation(child)\n\n// scale\nscale := transform.WorldScale(child)\n```\n\nHow to remove chidren (= destroy entities):\n\n```go\n// Remove children\ntransform.RemoveChildrenRecursive(parent)\n\n// Remove children and the parent\ntransform.RemoveRecursive(parent)\n```\n\n### Events\n\nThe [events package](https://pkg.go.dev/github.com/yohamta/donburi/features/events) allows us to send arbitrary data between systems in a Type-safe manner.\n\nThis package was adapted from [ariplane](https://github.com/m110/airplanes)'s code, which is created by [m110](https://github.com/m110). \n\nFor example:\n```go\n\nimport \"github.com/yohamta/donburi/features/events\"\n\n// Define any data\ntype EnemyKilled struct {\n  EnemyID int\n}\n\n// Define an EventType with the type of the event data\nvar EnemyKilledEvent = events.NewEventType[EnemyKilled]()\n\n// Create a world\nworld := donburi.NewWorld()\n\n// Add handlers for the event\nEnemyKilledEvent.Subscribe(world, LevelUp)\nEnemyKilledEvent.Subscribe(world, UpdateScore)\n\n// Sending an event\nEnemyKilledEvent.Publish(world, EnemyKilled{EnemyID: 1})\n\n// Process specific events\nEnemyKilledEvent.ProcessEvents(world)\n\n// Process all events\nevents.ProcessAllEvents(world)\n\n// Receives the events\nfunc LevelUp(w donburi.World, event EnemyKilled) {\n  // .. processs the event for levelup\n}\n\nfunc UpdateScore(w donburi.World, event EnemyKilled) {\n  // .. processs the event for updating the player's score\n}\n```\n\n## Projects Using Donburi\n\n### Games\n\n- [airplanes](https://github.com/m110/airplanes) - A 2D shoot 'em up game by [m110](https://github.com/m110)\n- [goingo](https://github.com/joelschutz/goingo) - Go game implemented in the Go language by [joelschutz](https://github.com/joelschutz)\n- [revdriller](https://github.com/yohamta/revdriller) - An action puzzle game by yohamta\n\n### Libraries\n- [necs](https://github.com/leap-fish/necs) - Networked Entity Component System; a networking layer for donburi by [gin](https://github.com/imthatgin)\n- [tamago](https://github.com/thefishhat/tamago) - CLI Runtime editor for donburi ECS Worlds by [thefishhat](https://github.com/thefishhat)\n\n## Architecture\n\n![arch](assets/architecture.png)\n\n## How to contribute?\n\nFeel free to contribute in any way you want. Share ideas, questions, submit issues, and create pull requests. Thanks!\n\n## Contributors\n\n\u003ca href=\"https://github.com/yohamta/donburi/graphs/contributors\"\u003e\n  \u003cimg src=\"https://contrib.rocks/image?repo=yohamta/donburi\" /\u003e\n\u003c/a\u003e\n\nMade with [contrib.rocks](https://contrib.rocks).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyohamta0%2Fdonburi-ecs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyohamta0%2Fdonburi-ecs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyohamta0%2Fdonburi-ecs/lists"}