Property Mapping ā #[gdbevy(...)] Grammar
This page was previously "Property Mapping with BevyBundle". The
BevyBundlemacro is gone; the unified#[gdbevy(...)]attribute replaces it on both bridging derives.
Both GodotNode (component-first) and BevyComponents (Godot-first) accept #[gdbevy(...)] annotations. The keys available depend on which derive you are using.
Component-first (GodotNode)
Companion component ā newtype
Generate one exported property and wrap its value in a newtype component:
#![allow(unused)] fn main() { #[derive(Component, GodotNode, Default)] #[gdbevy(base = CharacterBody2D, class_name = Player2D)] #[gdbevy(require(speed: Speed, as = f32, default = 250.0))] pub struct Player; }
speedbecomes a#[export] speed: f32on the generatedPlayer2Dclass (default 250.0).- When the node enters the tree,
Speed(speed_value)is inserted. as = f32is required here ā the macro cannot seeSpeed's inner type.
Companion component ā struct
Generate multiple exported properties for a multi-field component:
#![allow(unused)] fn main() { #[derive(Component, GodotNode, Default)] #[gdbevy(base = CharacterBody2D, class_name = Enemy2D)] #[gdbevy(require(stats: Stats { health(as = f32, default = 100.0), mana(as = f32, default = 50.0), }))] pub struct Enemy; }
Each inner field(as = T, ā¦) follows the same as/default/with grammar as the newtype form. The name before : (e.g. stats) is required by the grammar but ignored ā the generated export properties use the inner field names (health, mana).
Inspector metadata for generated exports
Metadata can be placed on a named or tuple primary field with
#[gdbevy(export, ...)], on require(prop: Comp, ...), or on each field inside
require(group: Comp { field(as = T, ...), ... }). Use one attribute per primary field.
Export types must implement gdext's Export trait. Rust String does not, so
export a GString and convert it when constructing the component:
#![allow(unused)] fn main() { use bevy::prelude::Component; use godot::prelude::GString; use godot_bevy::prelude::GodotNode; #[derive(Component)] pub struct WeaponKind(pub String); #[derive(Component, GodotNode, Default)] #[gdbevy(class_name = WeaponNode)] #[gdbevy(require( kind: WeaponKind, as = GString, with = from_godot_string, default = GString::from("Hands"), description = "Weapon selected by the designer", hint = ENUM, hint_string = "Hands,Knife" ))] pub struct Weapon; fn from_godot_string(value: GString) -> String { value.to_string() } }
description takes a string literal. Primary field /// docs are copied before
an explicit description. hint names a bare Godot PropertyHint variant, and
hint_string takes an expression. A hint string requires a hint.
Enable the register-docs feature on your godot-bevy dependency to register
property descriptions in Godot's editor:
godot-bevy = { version = "0.12", features = ["register-docs"] }
This feature is off by default and requires Godot API 4.3 or later. With it off, hints still work and descriptions remain Rust docs. API 4.2 consumers must leave it disabled.
Marker companion
Insert a component via Default with no exported property:
#![allow(unused)] fn main() { #[gdbevy(require(Stunned))] }
Primary field with conversion
Fields on the component struct itself can declare a type conversion:
#![allow(unused)] fn main() { #[derive(Component, GodotNode, Default)] #[gdbevy(base = Node2D, class_name = Slider2D)] pub struct Slider { /// Editor shows 0ā100; component gets 0.0ā1.0 #[gdbevy(export, as = f32, with = percentage_to_fraction)] pub value: f32, } fn percentage_to_fraction(v: f32) -> f32 { v / 100.0 } }
as = T is optional when the field type already implements gdext's Export trait; add it only when the export type differs from the Rust field type.
Tuple fields
Tuple structs are supported for component-first nodes. Exported fields are named value0, value1, and so on in the generated Godot class.
#![allow(unused)] fn main() { #[derive(Component, GodotNode, Default)] pub struct Velocity( #[gdbevy(export)] f32, #[gdbevy(export)] f32, ); }
All component-first keys
| Placement | Key | Required? | Meaning |
|---|---|---|---|
| struct | base = GodotBase | no (default: Node) | Godot class to extend |
| struct | class_name = Name | no (default: <Struct>BevyComponent) | Generated class name |
| struct | require(ā¦) | no | Companion component (see forms above) |
| field | export | yes | Marks the field as a generated Godot export |
| field | as = T | no | Godot export type |
| field | default = expr | no | Editor default (via #[init(val = ā¦)]); a pure-Bevy spawn(T) uses the struct's own Default ā make them agree if you rely on spawn(T). |
| field | with = fn | no | Godot-value ā field-value conversion |
require(prop: Comp, ā¦) | as = T | yes | Export type for the generated property |
require(prop: Comp, ā¦) | default = expr | no | Export default |
require(prop: Comp, ā¦) | with = fn | no | Conversion before constructing the component |
| generated primary or companion field | description = "..." | no | Property docs, registered with register-docs |
| generated primary or companion field | hint = NAME | no | Bare Godot PropertyHint variant |
| generated primary or companion field | hint_string = expr | no | Hint string, requires hint |
Godot-first (BevyComponents)
Field binding
Map a single #[export] property to a newtype component:
#![allow(unused)] fn main() { #[derive(GodotClass, BevyComponents)] #[class(base = Node2D, init)] pub struct EnemyNode { base: Base<Node2D>, #[gdbevy(component = Health)] #[export] max_health: f32, #[gdbevy(component = Speed, with = to_speed)] #[export] #[init(val = 100.0)] speed: f32, } }
component = Comp is required. with = fn is optional. as and default are not allowed ā gdext's #[init(val = ā¦)] owns defaults on this path.
Marker at the struct level
#![allow(unused)] fn main() { #[derive(GodotClass, BevyComponents)] #[class(base = CharacterBody2D, init)] #[gdbevy(require(Player))] pub struct PlayerNode { base: Base<CharacterBody2D>, // ... } }
Nā1 binding
Build a multi-field component from several existing #[export] properties:
#![allow(unused)] fn main() { #[derive(GodotClass, BevyComponents)] #[class(base = CharacterBody2D, init)] #[gdbevy(require(Stats { health: max_health, mana: max_mana }))] pub struct PlayerNode { base: Base<CharacterBody2D>, #[export] max_health: f32, #[export] max_mana: f32, } }
All Godot-first keys
| Placement | Key | Required? | Meaning |
|---|---|---|---|
| struct | require(Marker) | no | Insert Marker::default() |
| struct | require(Comp { bevy_field: godot_field, ⦠}) | no | Build struct component from existing exports |
| field | component = Comp | yes | Bevy component type (Comp(value)) |
| field | with = fn | no | Godot-value ā component-value conversion |
Godot-first classes own their gdext declaration, so use gdext's native
#[var(hint = ..., hint_string = ...)] and Rust documentation attributes for
Inspector metadata on those fields.
Native property descriptions also require godot-bevy/register-docs and Godot
API 4.3 or later. Keep metadata on the native attributes, outside gdbevy.
Reserved keys
into and sync are reserved for the upcoming component-sync feature and will produce a compile error if used. Use only the keys documented above.