# HudHandle

> Talos 0.6 · Since 0.6

HUD overlay.

Text values are keys into `meta.strings`; a missing key renders as `[[key]]`.

Reached in a behaviour as `ctx.hud`.

## Signature

```ts
export interface HudHandle {
  set(field: HudField, value: string | number | null): void
  objective(textKey: string): void
  /** A contextual prompt ("Press E"); null hides it. */
  prompt(textKey: string | null): void
  /** Countdown in seconds; null hides it. */
  timer(seconds: number | null): void
  score(value: number): void
  /**
   * Let one HUD row answer the hit-test and take focus.
   *
   * The HUD is click-through, so nothing on it can be clicked or tabbed to and it can never
   * quietly eat a gameplay click. This is the opt-in, and it grants both halves at the node:
   * the row is hit-testable *and* focusable, because §2.9 states the two together.
   *
   * In practice that is the pointer half. Tab, Enter and Space go to the topmost screen that
   * is not click-through, and the HUD is click-through so Escape still reaches the game over
   * a bare one — so an opted-in row is clickable rather than tabbable. A HUD node that has to
   * take the keyboard belongs on a screen that takes input.
   *
   * The field need not have a row yet — the opt-in is remembered and applies the moment `set`
   * writes one. It is not a {@link UiProp}: a binding cannot change what a node is, so this
   * re-registers the stock screen, once per opt-in rather than once per frame.
   */
  hittable(field: HudField | string, on?: boolean): void
}
```

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

## Members

| Member | Signature | Description |
|---|---|---|
| `set` | `set(field: HudField, value: string \| number \| null): void` |  |
| `objective` | `objective(textKey: string): void` |  |
| `prompt` | `prompt(textKey: string \| null): void` | A contextual prompt ("Press E"); null hides it. |
| `timer` | `timer(seconds: number \| null): void` | Countdown in seconds; null hides it. |
| `score` | `score(value: number): void` |  |
| `hittable` | `hittable(field: HudField \| string, on?: boolean): void` | Let one HUD row answer the hit-test and take focus. The HUD is click-through, so nothing on it can be clicked or tabbed to and it can never quietly eat a gameplay click. This is the opt-in, and it grants both halves at the node: the row is hit-testable *and* focusable, because §2.9 states the two together. In practice that is the pointer half. Tab, Enter and Space go to the topmost screen that is not click-through, and the HUD is click-through so Escape still reaches the game over a bare one — so an opted-in row is clickable rather than tabbable. A HUD node that has to take the keyboard belongs on a screen that takes input. The field need not have a row yet — the opt-in is remembered and applies the moment `set` writes one. It is not a {@link UiProp}: a binding cannot change what a node is, so this re-registers the stock screen, once per opt-in rather than once per frame. |

## Example

The tested fixture `fixtures/host/door.ts`.

```ts
import type { Behavior } from "@argus/api"
// docs/API.md, "Joints": a door on a hinge that swings open while the player is near and closes
// behind them. Typechecked by packages/api's tests.
export default {
  update(ctx) {
    const player = ctx.world.find("player")
    const near = player !== null && ctx.entity.distanceTo(player) < 2
    ctx.joint?.setMotor(near ? Math.PI / 2 : 0, { mode: "position", maxForce: 200 })
  },
} satisfies Behavior
```
