{"id":15168511,"url":"https://github.com/ggraca/belts","last_synced_at":"2025-09-06T11:34:55.547Z","repository":{"id":41318406,"uuid":"442016094","full_name":"ggraca/belts","owner":"ggraca","description":"A data-oriented game engine for Ruby","archived":false,"fork":false,"pushed_at":"2024-04-19T15:24:34.000Z","size":5901,"stargazers_count":12,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-31T07:11:48.898Z","etag":null,"topics":["3d-graphics","belts","data-oriented","game-development","game-engine","opengl","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ggraca.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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}},"created_at":"2021-12-27T01:04:18.000Z","updated_at":"2024-07-23T17:39:34.000Z","dependencies_parsed_at":"2023-12-31T01:38:32.128Z","dependency_job_id":"7830c18e-319a-4fcf-8550-21dc9c325431","html_url":"https://github.com/ggraca/belts","commit_stats":{"total_commits":70,"total_committers":2,"mean_commits":35.0,"dds":0.05714285714285716,"last_synced_commit":"643658ccb621000d6a9260819cf593a03e020446"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggraca%2Fbelts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggraca%2Fbelts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggraca%2Fbelts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggraca%2Fbelts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ggraca","download_url":"https://codeload.github.com/ggraca/belts/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238147555,"owners_count":19424283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["3d-graphics","belts","data-oriented","game-development","game-engine","opengl","ruby"],"created_at":"2024-09-27T06:04:32.979Z","updated_at":"2025-02-10T16:30:58.342Z","avatar_url":"https://github.com/ggraca.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Belts\n\n[//]: # \"Add badges here. Gem version, Github Actions build passing and CodeClimate\"\n\nBelts is a data-oriented game engine for the ruby programming language, heavily inspired by Ruby on Rails and Unity's DOTS.\n\nIn data-oriented game development, components hold data and systems execute game logic. Belts takes advantage of this to make code more descriptive and allow plugins to hook into the main loop, enabling or disabling features based on the developers' needs.\n\nBelts is designed to be easy to pick up and get something out there, ideal for hackathons and low demanding games. While performance improvements are welcome, the bulk of the features in the pipeline aim to target developer happiness (scaffolding, testing, plugin support, etc.)\n\n# Getting Started\n\n## Install\n\nInstall belts globally. Make sure you're running **ruby \u003e= 3.1.2** and have [OpenGL/GLFW](https://www.glfw.org/) and [CGLM](https://github.com/recp/cglm) available in your system:\n\n```bash\ngem install belts\n```\n\n## Create a new project\n\nRun the belts new command line. This will create a new folder with all the necessary files to get started:\n\n```bash\nbelts new my_game\n```\n\nAfter you create the new game, switch to its folder and start it:\n\n```bash\ncd my_game\nbelts start\n```\n\n[//]: # \"Add gif of the demo scene\"\n\n# Usage\n\n## Concepts\n\nA fresh project comes with a few basic examples. But to understand them we need to dive into what each of the folders in `app/` represents:\n\n```\napp/\n  components/\n  prefabs/\n  scenes/\n  systems/\n```\n\n### Components\n\nComponents are just simple structs to hold data. Other tools will be responsible for reading and modifying their values during runtime. They can also serve as tags if they don't hold any attribtues.\n\n```ruby\n# built-in component\nTransform = Struct.new(:position, :rotation, :scale)\n\n# app/components/spinner.rb\nSpinner = Struct.new(nil)\n```\n\n### Entities\n\nThere isn't a folder for entities because they only exist during runtime. They hold any number of Components and represent game objects: the player, the camera, an enemy or a just a cube.\n\n### Prefabs\n\nPrefabs are blueprints of entities. They are used to describe what entities should look like and can be saved for later use. They can be instantiated during runtime or from scenes.\n\n```ruby\nclass SpinningCube \u003c BeltsEngine::Prefab\n  component :render_data, RenderData.new(:cube, Vec3.right)\n  component :spinner, Spinner.new\nend\n```\n\n### Scenes\n\nScenes declare the initial state of a game level. You just need to specify the prefabs to use and where they should be placed.\n\n```ruby\nclass MainScene \u003c BeltsEngine::Scene\n  prefab :Camera3d, position: Vec3.back * 5\n  prefab :SpinningCube, position: Vec3.zero\nend\n```\n\n### Systems\n\nLastly, systems! Systems are where all game logic happens.\n\nEach system is initialised once and then called each frame:\n\n```ruby\nclass FrameCountSystem \u003c BeltsEngine::System\n  def start\n    @current_frame = 0\n  end\n\n  def update\n    puts @current_frame\n    @current_frame += 1\n  end\nend\n```\n\nWhile there are some use cases for simple systems like the one above, most of the time they will interact with entities and their components.\n\nThey way to do this is by specifying a **collection**. Behind the scenes, collections are automatically updated when components are added or removed from entities or when these are instantiated or destroyed. This ensures a system will only iterate over the small subset of entities it needs to.\n\n```ruby\nclass SpinnerSystem \u003c BeltsEngine::System\n  collection :spinners,\n    with: [:transform, :spinner]\n\n  def update\n    speed = @time.delta_time * 30\n\n    spinners.each_with_components do |transform:, **|\n      transform.rotate(speed, speed, speed)\n    end\n  end\nend\n```\n\n## Adding functionality to Systems with Tools\n\nTools are libraries, independent from the current scene. They are accessible from all systems and can hold global data. The core engine includes a few tools by default but more can be added by plugins, which is the expected way to add new features in the future (audio, asset management, physics).\n\nFrom any system, you can inspect the contents of `@game.tools` to see what tools have been installed. Then you can access any of these tools through the game object (e.g. `@game.time`) or using the short version (e.g. `@time`)\n\n### Entities\n\nIn order to change what entities show in collections, you might want to change their components entirely. There are few methods you can use to make this:\n\n```ruby\n@entities.instantiate(prefab_class, position, rotation)\n@entities.add_components(id, {spinner: Spinner.new, other_component: OtherComponent.new})\n@entities.remove_components(id, [:component_name])\n@entities.destroy(id)\n```\n\n### Time\n\nTime includes two read-only properties:\n\n```ruby\n@time.uptime # time since the game started\n@time.delta_time # time since last frame\n```\n\n### Input\n\nInput gives access to information about the keyboard and mouse state. Examples:\n\n```ruby\n@input.key?(:a) # true if A is being pressed\n@input.key_down?(:a) # true once, when A is pressed down\n@input.key_up?(:a) # true once, when A is released\n\n@input.button?(:mouse_1) # true if the mouse 1 button is being pressed\n@input.button_down?(:mouse_1) # true once, when the mouse 1 button is pressed down\n@input.button_up?(:mouse_1) # true once, when the mouse left button is released\n\n@input.mouse(:x) # x position on the screen in pixels (from top-left)\n@input.mouse(:y) # y position on the screen in pixels (from top-left)\n```\n\n# Future Work\n\nWork on Belts is in early stage and things are **very** likely to be renamed, moved or completely rebuilt.\n\nFuture work will focus more on the core engine instead of plugins. Today Belts ships with opengl but tomorrow might ship with vulkan or a 2d framework. This is what's planned next:\n\n- Documentation\n- Scaffold new projects with tests and testing guidelines (and add tests to this repo)\n- Scaffold new projects with standardrb (and add standardrb and code coverage to this repo)\n- Hot Reload for systems (change the logic without restarting the game)\n- Allow specifying systems order\n- C or Rust bindings for demanding snippets\n- Docker?\n\nWe'll continue to add basic functionality to plugins too:\n\n- Debugger\n- 2D lib\n- Audio\n- RendererL: lights, mesh loaders, post processing\n- Physics\n- Networking / Sync\n\n# Contributing\n\nContributions are welcome in three forms:\n\n- Raising issues and PRs in this repository\n- Creating external plugins (which may be added to the default release or as an option during the project creation)\n- Sharing your demos (which we may link to from this repo)\n\n# License\n\nBelts is released under the [MIT License](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fggraca%2Fbelts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fggraca%2Fbelts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fggraca%2Fbelts/lists"}