{"id":27372753,"url":"https://github.com/metal-666/declarativegodot","last_synced_at":"2026-02-18T00:03:12.676Z","repository":{"id":282645244,"uuid":"918775451","full_name":"Metal-666/DeclarativeGodot","owner":"Metal-666","description":"An experimental Godot package that adds Flutter-like declarative tree building. Why did I make this?","archived":false,"fork":false,"pushed_at":"2025-03-16T02:08:04.000Z","size":19,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-27T04:16:16.280Z","etag":null,"topics":["declarative-programming","flutter","godot","source-generation"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/DeclarativeGodot","language":"C#","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/Metal-666.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}},"created_at":"2025-01-18T20:26:40.000Z","updated_at":"2025-07-13T23:56:01.000Z","dependencies_parsed_at":"2025-03-16T06:15:23.112Z","dependency_job_id":null,"html_url":"https://github.com/Metal-666/DeclarativeGodot","commit_stats":null,"previous_names":["metal-666/declarativegodot"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Metal-666/DeclarativeGodot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Metal-666%2FDeclarativeGodot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Metal-666%2FDeclarativeGodot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Metal-666%2FDeclarativeGodot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Metal-666%2FDeclarativeGodot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Metal-666","download_url":"https://codeload.github.com/Metal-666/DeclarativeGodot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Metal-666%2FDeclarativeGodot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29563298,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T21:50:49.831Z","status":"ssl_error","status_checked_at":"2026-02-17T21:46:15.313Z","response_time":100,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["declarative-programming","flutter","godot","source-generation"],"created_at":"2025-04-13T10:38:50.705Z","updated_at":"2026-02-18T00:03:12.660Z","avatar_url":"https://github.com/Metal-666.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DeclarativeGodot\n\nThis is a highly experimental (and unfinished) package that adds Flutter-like Node tree building to Godot.\n\n## Usage\n\n1. Install the package via Nuget: https://www.nuget.org/packages/DeclarativeGodot.\n2. Create a new Godot project (or open an existing one).\n3. Set any scene as the main scene. The declarative tree will be created alongside its contents (a Godot limitation, since you can't run a game without a main scene).\n4. Add a new script with `DeclarativeGodot.DSceneTree` as the base class.\n   1. Add the `[GlobalClass]` attribute.\n   2. Override the `_Initialize` method and call `base._Initialize()`.\n   3. Override the `CreateRoot` method. Here you can start building your ~~`Widget`~~ `DObject` tree.\n5. In Godot settings, set this class as the current Main Loop (Project \u003e Project Settings... \u003e Application \u003e Run \u003e Main Loop Type).\n6. Profit! I guess?\n\n## Concept and implementation\n\nWhen designing this package I attempted to recreate Flutter's declarative approach while keeping everything as simple as possible (you build your tree using nested `Widgets` (which are immutable) and when you want to make changes to it you call a function which rebuilds it).\n\nThe class hierarchy in DeclarativeGodot looks like this:\n\n|- `DSceneTree` - a class which you need to extend for the whole thing to work; extends `SceneTree`  \n|- `DObject` - a base class for tree nodes, similar to Flutter's `Widget`  \n  |- `DWidget` - a base class for creating your own nodes, similar to Flutter's `StatelessWidget`  \n  |- `DNodeBase` - a base class for all the Godot Nodes (more on that later)  \n    |- `DNode`  \n      |- `DNode2D`  \n        |- ...  \n      |- `DNode3D`  \n        |- ...  \n      |- ...\n\nThe `DObject` class has the following public properties:\n\n- `string? _Key` - similar to Flutter's `key` property. Tells the declarative tree to reuse the underlying `Node` after rebuilds.\n- `bool _RecreateNode` - if set to `true`, will force the tree to create a new `Node` during the rebuild. If this is set to `false` (the `bool` default) and the `_Key` to `null` (also the default), the tree will attempt to reuse a random `Node` of a corresponding type.\n\nUnlike Flutter, Godot allows each `Node` to have any number of child nodes. That's why the base `DObject` class has a `IEnumerable\u003cDObject\u003e GetChildren()` method. `DNodeBase` implements this via a `Children` property that you can assign. `DWidget` implements it via the `Build` method.\n\nNow the fun part - the declarative Godot Node counterparts. For this, source generation was used. The source generator would go over every type in the `GodotSharp` package which extends `Node`, and generate a `D*` wrapper (`DNode`, `DLabel`, `DSprite2D` etc). These wrappers expose all the same properties that the underlying node has. When the tree is (re)built, those properties will then be (re)assigned to the underlying node (which could be a newly created one or a reused one). All these properties are nullable. If a property is `null` (meaning it wasn't explicitly set), it will not be assigned, keeping the default/reused value of the `Node`.\n\nAdditionally, for all the `events` (`Signals`) of the underlying `Node`, a property is created (with an `On*` prefix) and automatically subscribed/unsubscribed.\n\nTo rebuild the tree call `Rebuild` from a `DObject` subclass or directly on your `DSceneTree` subclass.\n\n## Code example\n\n\u003e MyCustomTree.cs:\n\n```csharp\nusing DeclarativeGodot;\n\nusing Godot;\n\n[GlobalClass]\npublic partial class MyCustomTree : DSceneTree {\n\n\tpublic override void _Initialize() =\u003e\n\t\tbase._Initialize();\n\n\tpublic override DObject CreateRoot() =\u003e\n\t\tnew MyCustomWidget();\n\n}\n```\n\n\u003e MyCustomWidget.cs:\n\n```csharp\nusing DeclarativeGodot;\n\nusing Godot;\n\npublic class MyCustomWidget : DWidget {\n\n\tprotected override DObject Build() =\u003e\n\t\tnew DControl() {\n\t\t\tOnReady =\n\t\t\t\t() =\u003e GD.Print(\"The widget is ready!\"),\n\t\t\tChildren = [\n\t\t\t\tnew DVBoxContainer() {\n\t\t\t\t\tChildren = [\n\t\t\t\t\t\tnew DLabel() {\n\t\t\t\t\t\t\tText = \"Hello world!\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnew DButton() {\n\t\t\t\t\t\t\tText = \"Exit\",\n\t\t\t\t\t\t\tOnPressed =\n\t\t\t\t\t\t\t\t() =\u003e (Engine.GetMainLoop() as SceneTree)?.Quit()\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t};\n\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetal-666%2Fdeclarativegodot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetal-666%2Fdeclarativegodot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetal-666%2Fdeclarativegodot/lists"}