---
title: "@command"
description: Labels a generator method for editors, with its parameters and a default duration, so a timeline can offer it without knowing the class.
---

Every generator method on an actor is a command a script can call. `@command` adds what an
editor needs to offer it to a person: a label, the parameters and their kinds, and a default
duration.

```ts twoslash title="card.ts"
import { command, LayoutActor, type Duration } from "@motionactor/core";

export class Card extends LayoutActor {
  @command({ label: "Reveal", duration: { default: 0.4 } })
  *reveal(duration: Duration = 0.4) {
    yield* this.appearance.opacity.tween(1, duration);
  }

  @command({
    label: "Move to",
    params: {
      x: { kind: "number", label: "X" },
      y: { kind: "number", label: "Y" },
    },
    duration: { default: 0.6 },
  })
  *moveTo({ x, y }: { x: number; y: number }, duration: Duration = 0.6) {
    yield* this.runtime.all(
      this.layout.x.tween(x, duration),
      this.layout.y.tween(y, duration),
    );
  }
}
```

A decorated command takes one of two shapes. Without `params`, its only argument is the
duration. With `params`, it takes an object of those parameters first and the duration
second, and calling it with anything but an object first throws.

## Options

| Option | |
| --- | --- |
| `label` | The name an editor shows. Required |
| `params` | Per parameter: `kind`, and optional `label`, `description`, `options` and `fields` |
| `duration` | `default`, and optional `label` and `description` |

A parameter's `kind` is `"string"`, `"number"`, `"boolean"`, `"color"`, `"enum"` (with
`options`), `"object"` (with nested `fields`, for a point such as `{ x, y }`) or `"json"`.

`duration.default` is what an editor fills in. A script that calls the method gets the
method's own default, so keep the two the same.

## Reading it

[Reflection](/docs/runtime/compiled-scene#reflection) lists an actor's decorated commands, sorted
by name:

```ts twoslash
// @filename: card.ts
import { command, LayoutActor, type Duration } from "@motionactor/core";
export class Card extends LayoutActor {
  @command({ label: "Reveal", duration: { default: 0.4 } })
  *reveal(duration: Duration = 0.4) {
    yield* this.appearance.opacity.tween(1, duration);
  }
  @command({
    label: "Move to",
    params: {
      x: { kind: "number", label: "X" },
      y: { kind: "number", label: "Y" },
    },
    duration: { default: 0.6 },
  })
  *moveTo({ x, y }: { x: number; y: number }, duration: Duration = 0.6) {
    yield* this.runtime.all(
      this.layout.x.tween(x, duration),
      this.layout.y.tween(y, duration),
    );
  }
}
// @filename: reflect.ts
// ---cut---
import { reflectBlueprint } from "@motionactor/core";
import { Card } from "./card";

reflectBlueprint(Card).commands.map((c) => c.label);
// ["Move to", "Reveal"]
```

`compiled.reflect(frame)` gives the same list for each spawned actor. Undecorated generator
methods still work from code. They are left out of the list because an editor would have
nothing to label them with.
