# Actor parameters

Actor parameters are properties on actors that you can set in the editor for each instance of an actor. This allows you to control the functionality of an actor without having to change code.

Parameters can be created by adding the `@Parameter()` decorator on a property in your actor class. The type of the parameter will be inferred by your property's type annotation.

### Supported Types

The example below shows all currently supported types.

```typescript
@Actor()
class ActorWithParameters extends BaseActor {
    @Parameter() aNumber: number
    @Parameter() aBoolen: boolean
    @Parameter() aString: string
    @Parameter() vec2: THREE.Vector2
    @Parameter() vec3: THREE.Vector3
    @Parameter() color: THREE.Color
    @Parameter() rotation: THREE.Euler
    
    // An instance of a 3D model asset
    @Parameter() mesh: THREE.Object3D
    
    // An instance of a material
    @Parameter() material: THREE.Material
    
    // An audio buffer from an audio asset
    @Parameter() audio: AudioBuffer
    
    @Parameter() clip: THREE.AnimationClip
    
    // Refer to another actor in the scene. 
    // You can also use your own actor class to only be 
    // able to select actors of that type
    @Parameter() actor: BaseActor
    
    @Parameter() prefab: Prefab
    @Parameter() specificPrefab: PrefabOf<WeaponActor>
}
```

#### Parameter Definitions

Use `@ParameterDefinition()` when a parameter should be a structured object instead of a single value. This is useful when several values belong together, or when you want designers to choose between different kinds of configuration that share a common base type.

The string passed to `@ParameterDefinition()` is the stable id stored in scene and prefab data. Choose an id that will not change when you rename or move the TypeScript class.

For example, an ability can contain several values that should be edited together:

```typescript
@ParameterDefinition('combat.damage')
class DamageDefinition {
  @Parameter() amount: number = 10
  @Parameter() damageType: string = 'physical'
}

@Actor()
class DamageZoneActor extends BaseActor {
  @Parameter()
  damage: DamageDefinition = new DamageDefinition()
}
```

In the editor, `damage` appears as a nested parameter group with `amount` and `damageType` inside it. At runtime, the actor receives an instance of `DamageDefinition`, so you can also add methods to the class if that makes the gameplay code clearer.

**Polymorphic Definitions**

Parameter definitions can extend other parameter definitions. If an actor parameter is typed as a base definition, the editor lets the designer select any registered subclass.

```typescript
@ParameterDefinition('combat.attack')
class AttackDefinition {
  @Parameter() damage: number = 10

  apply(target: BaseActor) {
    // Shared attack behavior
  }
}

@ParameterDefinition('combat.magicAttack')
class MagicAttackDefinition extends AttackDefinition {
  @Parameter() manaCost: number = 5

  override apply(target: BaseActor) {
    // Magic-specific behavior
  }
}

@Actor()
class WeaponActor extends BaseActor {
  @Parameter()
  attack: AttackDefinition = new AttackDefinition()
}
```

The designer can keep the base `AttackDefinition` or switch the parameter to `MagicAttackDefinition`. When a subclass is selected, its extra parameters are shown in the editor and the runtime value is an instance of that subclass.

Class names are converted into readable labels in the editor. For example, `MagicAttackDefinition` is shown as `Magic Attack`. The `Definition` suffix is optional, but using it is a good convention for these data classes.

**Abstract Base Definitions**

Sometimes the base type exists only to define a shared shape or API, and should not be selectable by itself. Mark it as abstract with the second argument to `@ParameterDefinition()`.

```typescript
@ParameterDefinition('combat.ability', { abstract: true })
abstract class AbilityDefinition {
  @Parameter() cooldown: number = 1

  abstract activate(owner: BaseActor): void
}

@ParameterDefinition('combat.fireball')
class FireballDefinition extends AbilityDefinition {
  @Parameter() radius: number = 3

  activate(owner: BaseActor) {
    // Fireball behavior
  }
}

@Actor()
class AbilityActor extends BaseActor {
  @Parameter()
  ability: AbilityDefinition
}
```

The editor will show a type selector for `ability`, but the designer must choose a concrete subclass such as `FireballDefinition` before nested fields are shown. This is useful for things like abilities, attacks, loot rules, AI actions, or other gameplay definitions where the base class is not meaningful on its own.

**Arrays of Definitions**

Parameter definitions can also be used in arrays.

```typescript
@Actor()
class AbilityBarActor extends BaseActor {
  @Parameter({ type: () => AbilityDefinition, array: true })
  abilities: AbilityDefinition[] = []
}
```

If the array element type has subclasses, each array item can use a different concrete definition. This makes it possible to build lists such as ability bars, attack combos, spawn tables, or status effects while keeping each item strongly typed in gameplay code.

### Parameter Options

You can pass a configuration object to the `@Parameter()` decorator to customize how the parameter behaves and appears in the editor.

```typescript
interface ParameterOptions {
  label?: string      // Custom display name in the editor
  help?: string       // Tooltip text shown on hover
  
  // Number configuration
  range?: [min, max]  // Slider with minimum and maximum values
  stepSize?: number   // Increment size for the input
  precision?: number  // Number of decimal places
  
  // Logic
  optional?: boolean  // Adds a checkbox to enable/disable the parameter (override mode)
  requires?: Record<string, unknown> // Only show this parameter if another property matches a value
}
```

#### Examples

**Numeric Sliders**

Use `range` to create a slider constraint, which is helpful for values like percentage or intensity.

```typescript
@Parameter({
  label: 'Movement Speed',
  range: [0, 100],
  stepSize: 1
})
speed: number = 10;
```

**Optional Overrides**

Use `optional` to allow a value to be null or undefined by default, unless explicitly enabled by the level designer. This is useful for overriding default behaviors.

```typescript
@Parameter({
  optional: true,
  help: 'If enabled, this color will override the default color'
})
customTint: THREE.Color = new THREE.Color('blue')
```

**Conditional Visibility**

Use `requires` to declutter the editor UI by hiding parameters that aren't relevant based on other settings.

```typescript
@Parameter()
canJump: boolean = false;

@Parameter({
  requires: { canJump: true } // Only visible when canJump is checked
})
jumpHeight: number = 2.0;
```

#### Prefab Types

Hology supports parameters that refer to prefab assets. While the generic `Prefab` type allows any prefab to be selected, the `PrefabOf<T>` type provides additional safety by restricting choices to prefabs that have a specific **Main Actor** [Prefab main actor](/gameplay/actors/prefab-main-actor.md)

For more details, see the [PrefabOf actor](/gameplay/actors/prefabof-actor.md) documentation.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.hology.app/gameplay/actors/actor-parameters.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
