Note: This reference documents the trait design space, not a promise that every listed trait has runtime behavior. Verify current trait files with
find packages/core/src/traits -name "*.ts" -not -name "*.test.*", and verify runtime/parser support from the package source before claiming a trait is implemented.
| Domain | Traits |
|---|---|
| Core Interaction | @grabbable @throwable @pointable @hoverable @scalable @rotatable @stackable @snappable @breakable @haptic @stretchable @moldable @interactive @clickable |
| Humanoid/Avatar | @skeleton @body @face @expressive @hair @clothing @hands @character_voice @locomotion @poseable @morph @avatar_embodiment @spectator @role |
| Environment | @plane_detection @mesh_detection @anchor @persistent_anchor @shared_anchor @geospatial @occlusion @light_estimation @geospatial_anchor @terrain_anchor @rooftop_anchor @vps @poi @world_locked |
| Input Modality | @eye_tracking @hand_tracking @controller @spatial_accessory @body_tracking @face_tracking |
| Accessibility | @accessible @alt_text @spatial_audio_cue @sonification @haptic_cue @magnifiable @high_contrast @motion_reduced @subtitle @screen_reader |
| Volumetric | @gaussian_splat @nerf @volumetric_video @point_cloud @photogrammetry |
| WebGPU Compute | @compute @gpu_particle @gpu_physics @gpu_buffer |
| Digital Twin & IoT | @sensor @digital_twin @data_binding @alert @heatmap_3d |
| Auto-Agents | @behavior_tree @goal_oriented @llm_agent @memory @perception @emotion @dialogue @faction @patrol @npc @dialog |
| Spatial Audio | @ambisonics @hrtf @reverb_zone @audio_occlusion @audio_portal @audio_material @head_tracked_audio @spatial_audio @ambient @voice_activated |
| Interoperability | @usd @gltf @fbx @material_x @scene_graph @portable |
| Web3 & Ownership | @nft @token_gated @wallet @marketplace |
| Physics | @cloth @fluid @soft_body @rope @chain @wind @buoyancy @destruction @physics @collidable @rigidbody @joint @trigger |
| State & Logic | @state @reactive @observable @computed @synced @persistent @owned @host_only |
| Visual Effects | @animation @timeline @choreography @particle @transition @filter @trail @glowing @emissive @transparent @reflective @animated @billboard @rotating @lod |
| Behavioral | @equippable @consumable @proactive @narrator |
Makes object pickable with hands/controllers.
template "Item" {
@grabbable
@grabbable(snap_to_hand: true)
@grabbable(haptic_on_grab: 0.7, two_handed: false)
geometry: "sphere"
}
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
snap_to_hand |
boolean | false |
Object snaps to grip position |
haptic_on_grab |
number | 0 |
Haptic intensity (0-1) |
two_handed |
boolean | false |
Requires both hands |
throw_on_release |
boolean | true |
Enable throwing |
Events: on_grab, on_release, on_grab_start, on_grab_end
Enables physics-based throwing.
template "Ball" {
@grabbable
@throwable
@throwable(velocity_multiplier: 2.0, bounce: true)
geometry: "sphere"
}
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
velocity_multiplier |
number | 1.0 |
Throw force multiplier |
bounce |
boolean | false |
Enable bouncing |
bounce_factor |
number | 0.5 |
Bounce energy retention |
max_velocity |
number | 50 |
Maximum throw speed |
Events: on_throw, on_land, on_bounce
Object stays in hand until button release.
template "Torch" {
@grabbable
@holdable(grip_button: "trigger")
geometry: "cylinder"
}
Object responds to click/tap/trigger.
template "Button" {
@clickable
@clickable(hold_time: 500ms, double_click: true)
geometry: "box"
on_click: { activate_door() }
}
Events: on_click, on_double_click, on_hold, on_release
Object responds to hover/gaze.
template "Indicator" {
@hoverable
@hoverable(scale_on_hover: 1.2, glow: true)
geometry: "sphere"
}
Events: on_hover_enter, on_hover_exit, on_hover
Object can be dragged in 2D/3D space.
template "Slider" {
@draggable(axis: "x", min: 0, max: 10)
geometry: "box"
}
Participates in collision detection.
template "Wall" {
@collidable
@collidable(layer: "environment", continuous: true)
geometry: "box"
}
Events: on_collision_enter, on_collision_exit, on_collision_stay
Full rigid body physics simulation.
template "Crate" {
@physics
@physics(mass: 5.0, drag: 0.1, angular_drag: 0.05)
geometry: "box"
}
Parameters:
| Parameter | Type | Default |
|---|---|---|
mass |
number | 1.0 |
drag |
number | 0 |
angular_drag |
number | 0.05 |
use_gravity |
boolean | true |
is_kinematic |
boolean | false |
freeze_rotation |
boolean | false |
Rigid body without gravity.
template "FloatingPlatform" {
@rigid
@collidable
geometry: "box"
}
Scripted movement that affects physics objects.
template "Elevator" {
@kinematic
@collidable
geometry: "box"
function move_up() {
animate position to [0, 10, 0] over 5s
}
}
Collision detection without physical response.
template "Zone" {
@trigger
geometry: "box"
on_trigger_enter: { start_battle() }
on_trigger_exit: { end_battle() }
}
Object affected by gravity.
template "GravityBall" {
@gravity
@gravity(strength: 9.81, direction: [0, -1, 0])
geometry: "sphere"
}
Object emits light.
template "Lamp" {
@glowing
@glowing(color: "#ff0000", intensity: 2.0, range: 10)
geometry: "sphere"
}
Self-illuminating material (no light emission to scene).
template "Sign" {
@emissive(color: "#00ffff", intensity: 1.5)
geometry: "plane"
}
Transparency/opacity control.
template "Glass" {
@transparent(opacity: 0.5, double_sided: true)
geometry: "box"
}
Mirror-like surface.
template "Mirror" {
@reflective(strength: 1.0, blur: 0)
geometry: "plane"
}
Object has animation states.
template "Character" {
@animated
geometry: "humanoid"
animations: {
idle: "idle.anim",
walk: "walk.anim",
run: "run.anim"
}
function start_walking() {
play_animation("walk")
}
}
Always faces the camera.
template "Label" {
@billboard
@billboard(lock_y: true) // Only rotate on Y axis
geometry: "plane"
}
Continuous rotation animation.
template "Spinner" {
@rotating
@rotating(speed: 45, axis: "y")
@rotating(speed: 90, axis: [1, 0, 1]) // Custom axis
geometry: "sphere"
}
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
speed |
number | 30 |
Rotation speed (degrees/second) |
axis |
string/array | "y" |
Rotation axis: "x", "y", "z", or [x,y,z] |
clockwise |
boolean | true |
Rotation direction |
paused |
boolean | false |
Start paused |
Events: on_rotation_start, on_rotation_pause, on_rotation_cycle
General interactivity marker (enables all input modes).
template "InteractiveButton" {
@interactive
@interactive(modes: ["click", "hover", "grab"])
@interactive(cursor: "pointer", highlight: true)
geometry: "box"
}
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
modes |
array | ["click", "hover"] |
Enabled interaction modes |
cursor |
string | "default" |
Cursor style on hover |
highlight |
boolean | true |
Highlight on interaction |
sound |
string | null |
Interaction sound effect |
Events: on_interact, on_focus, on_blur
Level of Detail switching for performance optimization.
template "ComplexModel" {
@lod
@lod(distances: [10, 30, 100])
@lod(levels: ["high.glb", "medium.glb", "low.glb"])
geometry: "mesh"
}
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
distances |
array | [10, 25, 50] |
Switch distances in meters |
levels |
array | null |
Model files for each LOD |
fade |
boolean | true |
Fade between LOD levels |
fade_duration |
number | 200 |
Fade duration in ms |
bias |
number | 0 |
Distance bias adjustment |
Events: on_lod_change
State syncs across network.
template "SharedObject" {
@networked
@networked(sync_rate: 30hz, interpolation: true)
geometry: "sphere"
}
Parameters:
| Parameter | Type | Default |
|---|---|---|
sync_rate |
frequency | 20hz |
interpolation |
boolean | true |
authority |
string | "server" |
Mark specific properties for sync.
template "SyncedPlayer" {
@synced(properties: [position, rotation, health])
geometry: "humanoid"
}
State persists between sessions.
template "SavePoint" {
@persistent
@persistent(key: "player_progress")
geometry: "cylinder"
}
Has network ownership (only owner can modify).
template "PlayerAvatar" {
@networked
@owned
geometry: "humanoid"
}
Only host can modify.
template "GameManager" {
@networked
@host_only
geometry: "box"
}
Objects can stack on each other.
template "Block" {
@stackable(axis: "y", max_stack: 10)
geometry: "box"
}
Object can attach to other objects.
template "Scope" {
@attachable(attach_points: ["weapon_rail"])
geometry: "cylinder"
}
Can be equipped to avatar slots.
template "Helmet" {
@equippable(slot: "head", auto_fit: true)
geometry: "sphere"
}
Object can be consumed/used up.
template "Potion" {
@consumable
geometry: "cylinder"
on_consume: {
player.health += 50
this.destroy()
}
}
Object can be destroyed.
template "DestructibleCrate" {
@destructible
@destructible(health: 100, fragments: 8, explosion: true)
geometry: "box"
on_destroy: { spawn_loot() }
}
Fixed position in world space.
template "Waypoint" {
@anchor
geometry: "sphere"
}
Follows a tracked point (controller, hand, etc).
template "Pointer" {
@tracked(source: "right_controller")
geometry: "cone"
}
Locked to world coordinates (AR).
template "ARMarker" {
@world_locked
geometry: "plane"
}
Follows hand skeleton.
template "Ring" {
@hand_tracked(hand: "left", joint: "ring_finger_tip")
geometry: "torus"
}
Responds to eye gaze with dwell activation and highlighting.
template "GazeTarget" {
@eye_tracked
@eye_tracked(dwell_enabled: true, dwell_time: 1000ms)
@eye_tracked(gaze_highlight: true, highlight_color: "#00ffff")
geometry: "sphere"
on_gaze_enter: { highlight() }
on_gaze_exit: { unhighlight() }
on_dwell_activate: { click() }
}
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
dwell_enabled |
boolean | true |
Enable dwell-to-activate |
dwell_time |
duration | 1000ms |
Time to dwell for activation |
dwell_feedback |
boolean | true |
Show progress indicator |
gaze_highlight |
boolean | true |
Highlight when gazed at |
highlight_color |
string | "#00ffff" |
Highlight color |
gaze_scale |
number | 1.1 |
Scale multiplier when gazed |
foveated_priority |
string | "medium" |
Rendering priority (low/medium/high) |
smooth_pursuit |
boolean | false |
Object follows gaze smoothly |
Events: on_gaze_enter, on_gaze_exit, on_dwell_progress, on_dwell_activate
Optimizes object for seated VR users with comfort options.
template "SeatedPlayer" {
@seated
@seated(auto_calibrate: true, snap_turn_angle: 45)
@seated(comfort_vignette: true, max_reach: 1.0)
geometry: "humanoid"
}
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
height_offset |
number | 0 |
Height adjustment (meters) |
max_reach |
number | 1.0 |
Maximum forward reach |
auto_calibrate |
boolean | true |
Auto-calibrate seated height |
comfort_vignette |
boolean | true |
Vignette on rotation |
snap_turn_angle |
number | 45 |
Snap turn degrees (0 = smooth) |
play_bounds |
array | [1.5, 1.5] |
Play area [width, depth] |
Events: on_seated_calibrated, on_turn_left, on_turn_right
Advanced haptic feedback with patterns and proximity.
template "VibratingObject" {
@haptic
@haptic(intensity: 0.7, collision_pattern: "metal")
@haptic(proximity_enabled: true, proximity_distance: 0.5)
geometry: "sphere"
}
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
intensity |
number | 0.5 |
Base haptic intensity (0-1) |
proximity_enabled |
boolean | false |
Enable proximity-based haptics |
proximity_distance |
number | 0.5 |
Distance for proximity haptics |
collision_pattern |
string | "soft" |
Pattern: soft/hard/metal/glass/custom |
hands |
string | "dominant" |
Which hands: both/left/right/dominant |
duration |
number | 100 |
Haptic pulse duration (ms) |
Built-in Patterns:
soft- Gentle taphard- Strong impactmetal- Metallic ringglass- Delicate break
Events: on_haptic_start, on_haptic_end
3D positional audio.
template "Speaker" {
@spatial_audio
@spatial_audio(falloff: "linear", max_distance: 20)
geometry: "box"
audio_source: "music.mp3"
}
Background audio source.
template "EnvironmentSound" {
@ambient(loop: true, volume: 0.5)
geometry: "sphere"
audio_source: "forest.mp3"
}
Responds to voice input.
template "VoiceController" {
@voice_activated
geometry: "sphere"
commands: {
"open door": { open_door() },
"lights on": { toggle_lights(true) }
}
}
Has reactive state.
template "Counter" {
@state
geometry: "box"
state {
count: 0
}
on_click: { state.count++ }
}
Automatically updates on state change.
template "Display" {
@reactive
geometry: "plane"
text: "Count: ${state.count}"
}
State can be observed by other objects.
template "HealthBar" {
@observable
geometry: "box"
state {
health: 100
}
}
template "HealthDisplay" {
@observe(target: "health_bar", property: "health")
geometry: "plane"
on_change: { update_display(value) }
}
Derived state from other values.
template "Stats" {
@state
geometry: "box"
state {
attack: 10
defense: 5
}
@computed power = attack * 2 + defense
}
LLM-powered decision-making with bounded autonomy.
template "Assistant" {
@llm_agent(model: "gemini-1.5-pro", context_window: 10)
geometry: "humanoid"
system_prompt: "You are a helpful museum guide."
@on_llm_response: (text) -> { speak(text) }
}
Declarative behavior tree for complex NPC logic.
template "Guard" {
@behavior_tree
geometry: "humanoid"
root: {
type: "selector",
children: [
{ type: "action", action: "attack", condition: "player_visible" },
{ type: "action", action: "patrol" }
]
}
}
WebGPU-accelerated compute shaders.
template "Simulation" {
@compute(shader_source: "fluid.wgsl", workgroup_size: [16, 16, 1])
geometry: "mesh"
@on_compute_complete: () -> { update_mesh() }
}
Note: This is a living document. For the current trait inventory, use the commands in docs/NUMBERS.md and inspect packages/core/src/traits/; do not rely on a copied count.