# ActionState

> Talos next · Since 0.6

One frame of an action button.

## Signature

```ts
export interface ActionState {
  /** Went down this frame. */
  pressed: boolean
  /** Is down. */
  held: boolean
  /** Went up this frame. */
  released: boolean
}
```

Import: `import type { ActionState } from "@argus/api"`

## Members

| Member | Signature | Description |
|---|---|---|
| `pressed` | `pressed: boolean` | Went down this frame. |
| `held` | `held: boolean` | Is down. |
| `released` | `released: boolean` | Went up this frame. |

## Example

The tested fixture `fixtures/recipes/best-score-save/scenes/behaviors/best-score-save.ts`.

```ts
import type { Behavior } from "@argus/api"

/**
 * A best score that outlives the run, kept with `ctx.save`.
 *
 * Space scores, Return ends the round, and the best is saved before the round restarts.
 *
 * `ctx.state` is wiped by `ctx.session.restart()`, by `loadScene` and by quitting; `ctx.save` is
 * not. So the best is read from the save in `init` — which runs again after every restart — and
 * written there the moment it is beaten, never kept only in state.
 */
interface State {
  score: number
  best: number
}

/** One store per application, so a key is worth namespacing: 1–64 of `A-Z a-z 0-9 . _ -`. */
const BEST = "best-score.best"

export default {
  init(ctx) {
    ctx.state.score = 0
    ctx.state.best = Number(ctx.save.get(BEST) ?? 0) || 0
    ctx.hud.score(0)
    ctx.hud.set("best", ctx.state.best)
  },

  update(ctx) {
    if (ctx.input !== null && ctx.input.pressed("score")) {
      ctx.state.score += 1
      ctx.hud.score(ctx.state.score)
    }
    if (ctx.input !== null && ctx.input.pressed("finish")) {
      if (ctx.state.score > ctx.state.best) {
        ctx.state.best = ctx.state.score
        ctx.save.set(BEST, ctx.state.best)
      }
      // Lands at the end of this tick; the save is written at the end of it too, first.
      ctx.session.restart()
    }
  },
} satisfies Behavior<State>
```
