| Header | Link |
|---|---|
| Purpose | Purpose |
| Use Cases | Use Cases |
| Practical Example | Practical Example |
| Reference | Reference |
Copy-and-paste field reference for every 3D node you place in a .scn scene: mesh instances, cameras, lights, physics bodies, skeletons, particles, water, and 3D audio geometry. Each template shows the exact block layout and field names so you can drop a node in and tune values without guessing. For node trees a script builds at runtime, use Node Collections.
- Place 3D geometry and world text:
MeshInstance3D,MultiMeshInstance3D,Sprite3D,Label3D,Decal3D. - Add a camera, lights, and sky:
Camera3D,PointLight3D,SpotLight3D,RayLight3D,AmbientLight3D,Sky3D. - Give things collision and physics:
StaticBody3D,RigidBody3D,CharacterBody3D, andArea3Dwith a childCollisionShape3D. - Rig, animate, and attach to skeletons:
Skeleton3D,CharacterSkeleton,BoneAttachment3D,AnimationPlayer,AnimationTree,IKTarget3D,PhysicsBoneChain3D. - Add particles, water, and audio geometry:
ParticleEmitter3D,WaterBody3D,AudioMask3D,AudioEffectZone3D,AudioPortal3D.
Choose a template by engine behavior first: transform, render, light, camera, or physics. Compose child nodes when one object needs several behaviors. Use typed asset fields for per-instance mesh/material/animation choices and inject their paths through script_vars; keep literal paths in code only for assets shared by every instance.
A minimal 3D scene: a mesh prop plus an active camera looking at it.
[prop]
parent = $root
[MeshInstance3D]
mesh = "res://models/barrel.glb:mesh[0]"
[Node3D]
position = (0, 0, 0)
[/Node3D]
[/MeshInstance3D]
[/prop]
[camera]
parent = $root
[Camera3D]
active = true
[Node3D]
position = (0, 2, 6)
[/Node3D]
[/Camera3D]
[/camera]
[node3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/node3d]
[mesh_instance_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[MeshInstance3D]
mesh = "res://path/to/model.glb:mesh[0]"
material = "res://path/to/material.pmat"
surfaces = [
"res://path/to/material0.pmat",
{
material = "res://path/to/material1.pmat"
modulate = (1, 0.9, 0.9, 1)
overrides = [
{ name = "roughness", value = 0.25 },
{ name = "shade_flat", value = true },
{ name = "rim_color", value = (0.2, 0.6, 1.0, 1.0) }
]
}
]
model = "res://path/to/model.glb"
skeleton = @SkeletonNodeName
# indexed glTF blend shape / morph target weights, clamped 0.0..1.0
# aliases: shape_key_weights, morph_weights
blend_shape_weights = [0.0, 0.2, 0.1]
flip_x = false
flip_y = false
flip_z = false
meshlets = true
blend = {
enabled = true
blend_layers = [1]
blend_mask = [1]
distance = 0.85
min_distance = 0.03
noise = 0.35
noise_scale = 14.0
slope_factor = 2.0
strength = 1.0
salt_instances = true
}
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/MeshInstance3D]
[/mesh_instance_3d]
[multi_mesh_instance_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[MultiMeshInstance3D]
mesh = "res://path/to/model.glb:mesh[0]"
material = "res://path/to/material.pmat"
surfaces = [
"res://path/to/material0.pmat",
{
material = "res://path/to/material1.pmat"
modulate = (1, 0.9, 0.9, 1)
overrides = [
{ name = "roughness", value = 0.25 },
{ name = "shade_flat", value = true }
]
}
]
# instance count = instances.len()
instance_scale = 1.0
# default blend shape weights for all instances
blend_shape_weights = [0.0, 0.2, 0.1]
flip_x = false
flip_y = false
flip_z = false
meshlets = true
# alternative to large explicit arrays:
# instance_grid = { counts=(20, 5, 10) spacing=(1.25, 1.0, 1.25) origin=(-12, 0, -6) scale=(1, 1, 1) scale_wave=0.1 height_wave=0.25 rotation_step_deg=(0, 15, 0) }
blend_enabled = true
blend_layers = [1]
blend_mask = [1]
blend_distance = 0.85
instances = [
{
position = (6, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
},
{
position = (6, 0, 0)
rotation_deg = (0, 45, 0)
scale = 0.75
blend_shape_weights = [1.0, 0.0, 0.5]
},
]
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/MultiMeshInstance3D]
[/multi_mesh_instance_3d]
Mesh blending uses screen-space depth to fade mesh intersections.
Only the mesh with `blend_enabled = true` fades.
Receiver meshes only need explicit `blend_layers`.
`blend_enabled = true` applies alpha fade and normal-assisted contact smoothing.
`blend_layers` tags a mesh for blend filtering.
`blend_mask` lists receiver layers the fading mesh ignores.
Default `blend_mask = []`, so enabled blending ignores nothing.
`slope_factor` (0..8, default 2.0) fades the seam on near-perpendicular contacts; 0 turns the slope falloff off.
`strength` (0..1, default 1.0) scales the overall seam blend amount.
`salt_instances` (default true) seams same-type multimesh instances against each other; false shares one seam id per batch (use with many multimesh sources).
Flat aliases: `blend_slope_factor`, `blend_strength`, `blend_salt_instances` (plus `blend_noise_factor`, `blend_noise_scale`).
[sprite3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[Sprite3D]
texture = "res://path/to/icon.png"
texture_region = (0, 0, 32, 32)
size = (1, 1)
flip_x = false
flip_y = false
modulate = (1, 1, 1, 1)
[Node3D]
position = (0, 1, -3)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/Sprite3D]
[/sprite3d]
[label3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[Label3D]
text = "Name"
# alt: text = %loc: "ui.nameplate"
# wrap width uses size aspect + font_size, not current camera projection
size = (1.5, 0.35)
color = (1, 1, 1, 1)
lock_orientation = false
backface_cull = true
# false: scene-depth test; true: draw as always-visible overlay
visible_through_objects = false
# sign style: set opaque backdrop + padding; defaults are transparent + zero
backdrop_color = (0, 0, 0, 0)
padding = (0, 0, 0, 0)
# UI ratio order: top-left, top-right, bottom-right, bottom-left
corner_radii = (0, 0, 0, 0)
font_size = 20
h_align = center
v_align = center
[Node3D]
position = (0, 1.8, -3)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/Label3D]
[/label3d]
[water_body_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[WaterBody3D]
shape = { type="cube", size=(128, 12, 128) }
resolution = (128, 128)
render_resolution = (256, 256)
lod_min_resolution = (32, 32)
depth = 12.0
flow = (0, 0)
wind = (1, 0)
idle_mode = "calm"
wave_speed = 1.0
wave_scale = 1.0
damping = 0.985
buoyancy = 1.0
drag = 0.35
wake_strength = 1.35
foam_strength = 0.9
sample_readback_rate = 30
lod_near = 128
lod_mid = 384
lod_far = 896
min_resolution = 32
collision_layers = [1]
collision_mask = []
coastline = { foam_color=(0.9, 0.97, 1.0, 1.0) foam_strength=0.75 foam_width=1.5 cutoff_softness=0.25 wave_reflection=0.45 wave_damping=0.35 edge_noise=0.2 }
debug = false
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/WaterBody3D]
[/water_body_3d]
[camera3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[Camera3D]
zoom = 0.0
projection = perspective
perspective_fov_y_degrees = 60.0
perspective_near = 0.1
perspective_far = 1000.0
orthographic_size = 10.0
orthographic_near = 0.1
orthographic_far = 1000.0
frustum_left = -1.0
frustum_right = 1.0
frustum_bottom = -1.0
frustum_top = 1.0
frustum_near = 0.1
frustum_far = 1000.0
post_processing = []
audio_options = { audio_mask=[], effects=[] }
active = false
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/Camera3D]
[/camera3d]
[camera_stream_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[CameraStream3D]
camera = @CameraNode
resolution = (512, 512)
aspect_ratio = 0.0
aspect_mode = "fit"
enabled = true
size = (1.0, 1.0)
tint = (1, 1, 1, 1)
post_processing = []
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/CameraStream3D]
[/camera_stream_3d]
[sub_view_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[SubView3D]
size = (1, 1)
resolution = (512, 512)
aspect_ratio = 0.0
aspect_mode = "fit"
view_position = (0, 0, 5)
view_rotation = (0, 0, 0, 1)
projection = "perspective"
perspective_fov_y_degrees = 60
view_2d_position = (0, 0)
view_2d_rotation = 0.0
view_2d_zoom = 1.0
background = "#00000000"
tint = (1, 1, 1, 1)
enabled = true
suspend_when_hidden = true
post_processing = []
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/SubView3D]
[/sub_view_3d]
[collision_shape_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[CollisionShape3D]
shape = { type = cube, size = (1, 1, 1) }
# alt: trimesh = "res://path/to/model.glb:mesh[0]"
# alt: shape = { type = trimesh source = "res://path/to/model.glb:mesh[0]" }
flip_x = false
flip_y = false
flip_z = false
debug = false
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/CollisionShape3D]
[/collision_shape_3d]
[static_body_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[StaticBody3D]
enabled = true
friction = 0.7
restitution = 0.0
density = 1.0
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/StaticBody3D]
[/static_body_3d]
[rigid_body_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[RigidBody3D]
enabled = true
continuous_collision_detection = true
mass = 1.0
linear_velocity = (0, 0, 0)
angular_velocity = (0, 0, 0)
gravity_scale = 1.0
linear_damping = 0.0
angular_damping = 0.0
can_sleep = true
friction = 0.7
restitution = 0.0
density = 1.0
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/RigidBody3D]
[/rigid_body_3d]
[character_body_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[CharacterBody3D]
enabled = true
friction = 0.7
restitution = 0.0
density = 1.0
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/CharacterBody3D]
[/character_body_3d]
[area3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[Area3D]
enabled = true
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/Area3D]
[/area3d]
[audio_mask_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[AudioMask3D]
active = true
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/AudioMask3D]
[/audio_mask_3d]
[audio_effect_zone_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[AudioEffectZone3D]
active = true
audio_mask = []
effects = [
{ reverb_send = 0.35 echo = 0.0 dampening = 0.0 }
]
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/AudioEffectZone3D]
[/audio_effect_zone_3d]
[audio_portal_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[AudioPortal3D]
active = true
strength = 1.0
targets = [@OtherPortal]
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/AudioPortal3D]
[/audio_portal_3d]
[skeleton3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[Skeleton3D]
skeleton = "res://path/to/model.glb:skeleton[0]"
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/Skeleton3D]
[/skeleton3d]
[bone_attachment_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[BoneAttachment3D]
skeleton = @SkeletonNodeName
bone = 0
# alt: bone_index = 0
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/BoneAttachment3D]
[/bone_attachment_3d]
[physics_bone_chain_3d]
[PhysicsBoneChain3D]
skeleton = @SkeletonNodeName
bone = 0
chain_length = 4
gravity = (0, -9.81, 0)
damping = 0.08
stiffness = 0.35
radius = 0.05
collisions = true
iterations = 3
[/PhysicsBoneChain3D]
[/physics_bone_chain_3d]
[bone_collider_3d]
[BoneCollider3D]
enabled = true
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/BoneCollider3D]
[/bone_collider_3d]
[ik_target_3d]
parent = PARENTKEY
script = "res://path/to/script.rs"
[IKTarget3D]
skeleton = @SkeletonNodeName
bone = 0
# alt: bone_index = 0
chain_length = 2
iterations = 8
tolerance = 0.01
weight = 1.0
match_rotation = true
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/IKTarget3D]
[/ik_target_3d]
[particle_emitter_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[ParticleEmitter3D]
active = true
looping = true
prewarm = false
spawn_rate = 256.0
seed = 1
params = []
profile = "res://path/to/profile.ppart"
sim_mode = default
render_mode = point
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/ParticleEmitter3D]
[/particle_emitter_3d]
[particle_emitter_2d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[ParticleEmitter2D]
active = true
looping = true
prewarm = false
spawn_rate = 256.0
seed = 1
params = []
profile = "res://path/to/profile.ppart"
sim_mode = default
[Node2D]
position = (0, 0)
rotation = 0
scale = (1, 1)
z_index = 0
visible = true
[/Node2D]
[/ParticleEmitter2D]
[/particle_emitter_2d]
BoneAttachment3D binds to a Skeleton3D node plus bone index.
Children then inherit that bone transform.
Use it for socket nodes, like a sword in a hand.
[CharacterSkeleton]
parent = @Character
[Skeleton3D]
skeleton = "res://characters/hero.glb:skeleton[0]"
[/Skeleton3D]
[/CharacterSkeleton]
[RightHandSocket]
parent = @Character
[BoneAttachment3D]
skeleton = @CharacterSkeleton
bone = 15
[/BoneAttachment3D]
[/RightHandSocket]
[Sword]
parent = @RightHandSocket
[MeshInstance3D]
mesh = "res://weapons/sword.glb:mesh[0]"
material = "res://weapons/sword.pmat"
[Node3D]
position = (0.05, 0.0, 0.0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/MeshInstance3D]
[/Sword]
[ambient_light_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[AmbientLight3D]
color = (1, 1, 1)
intensity = 0.0
cast_shadows = true
active = true
[/AmbientLight3D]
[/ambient_light_3d]
[sky3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[Sky3D]
day_colors = [
(0.55, 0.82, 1.0),
(0.38, 0.68, 0.95),
(0.18, 0.45, 0.82)
]
evening_colors = [
(1.00, 0.62, 0.40),
(0.95, 0.42, 0.58),
(0.42, 0.20, 0.42)
]
night_colors = [
(0.01, 0.02, 0.06),
(0.04, 0.06, 0.15),
(0.09, 0.12, 0.25)
]
horizon_colors = [
(0.62, 0.64, 0.66),
(0.42, 0.43, 0.45),
(0.28, 0.29, 0.31)
]
time = { time_of_day = 0.25 paused = false scale = 1.0 }
time_of_day = 0.25
time_paused = false
time_scale = 1.0
shaders = [
{ path = "res://path/to/sky.wgsl", params = [0.5, (1.0, 0.8, 0.6)] }
]
environment = {
source = "res://textures/studio.png"
intensity = 1.0
rotation_degrees = 0.0
}
active = true
[/Sky3D]
[/sky3d]
See [`Sky3D`](../../resources/sky3d.md) for custom sky shader authoring.
[ray_light_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[RayLight3D]
color = (1, 1, 1)
intensity = 1.0
cast_shadows = true
shadow = { strength = 0.82 depth_bias = 0.00003 normal_bias = 0.005 }
active = true
visible = true
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/RayLight3D]
[/ray_light_3d]
[point_light_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[PointLight3D]
color = (1, 1, 1)
intensity = 1.0
range = 10.0
cast_shadows = true
shadow_strength = 0.82
shadow_depth_bias = 0.00003
shadow_normal_bias = 0.005
active = true
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/PointLight3D]
[/point_light_3d]
[spot_light_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[SpotLight3D]
color = (1, 1, 1)
intensity = 1.0
range = 12.0
inner_angle_radians = 0.34906584
outer_angle_radians = 0.5235988
cast_shadows = true
shadow_strength = 0.82
shadow_depth_bias = 0.00003
shadow_normal_bias = 0.005
active = true
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/SpotLight3D]
[/spot_light_3d]
[decal_3d]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[Decal3D]
size = (1, 1, 1)
albedo_texture = "res://textures/decal.png"
normal_texture = ""
emission_texture = ""
modulate = (1, 1, 1, 1)
albedo_mix = 1.0
emission_energy = 1.0
normal_strength = 1.0
normal_fade = 0.3
distance_fade_begin = 0.0
distance_fade_length = 8.0
sort_priority = 0
active = true
[Node3D]
position = (0, 0, 0)
rotation = (0, 0, 0, 1)
scale = (1, 1, 1)
visible = true
[/Node3D]
[/Decal3D]
[/decal_3d]
Decal3D projects along its local -Z axis onto lit geometry inside the `size`
box, patching albedo/normal and adding emission before lighting (decals
receive shadows and lights like the surface under them). `normal_fade`
rejects grazing surfaces, `distance_fade_begin`/`distance_fade_length` fade
by camera distance (0 = never), higher `sort_priority` blends over lower.
[animation_player]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[AnimationPlayer]
animation = "res://path/to/clip.panim"
bindings = []
speed = 1.0
paused = false
playback = loop
[/AnimationPlayer]
[/animation_player]
[animation_tree]
parent = @PARENTKEY
script = "res://path/to/script.rs"
[AnimationTree]
tree = "res://path/to/tree.panimtree"
animations = [
{ animation = "res://path/to/idle.panim", bindings = { Hero = @PlayerRoot }, playback = loop, speed = 1.0, paused = false },
{ animation = "res://path/to/run.panim", bindings = { Hero = @PlayerRoot }, playback = loop, speed = 1.0, paused = false },
{ animation = "res://path/to/aim.panim", bindings = { Hero = @PlayerRoot }, playback = boomerang, speed = 1.0, paused = false },
]
speed = 1.0
paused = false
[/AnimationTree]
[/animation_tree]