# HudController

> Talos next · Since 0.6; changed in 0.7

## Signature

```ts
export class HudController {
  readonly strings: Strings
  readonly goals: GoalSpec[]
  readonly reached = new Set<string>()
  score = 0
  timeLeft: number | null = null
  constructor(ctx: Ctx, opts: HudOptions = {})
  static discoverGoals(ctx: Ctx): GoalSpec[]
  get currentGoal(): GoalSpec | null
  get total(): number
  get completed(): number
  get progressText(): string
  get done(): boolean
  start(): void
  complete(goalId: string): boolean
  handle(ev: GameEvent): boolean
  refresh(): void
  objective(textKey: string): void
  prompt(textKey: string | null): void
  timer(seconds: number | null): void
  startTimer(seconds: number): void
  stopTimer(): void
  setScore(value: number): void
  addScore(delta: number): void
  set(field: HudField, value: string | number | null, options?: HudFieldOptions): void
  update(dt: number): void
}
```

Import: `import { HudController } from "@argus/gameplay"`

## Members

| Member | Signature | Description |
|---|---|---|
| `strings` | `readonly strings: Strings` |  |
| `goals` | `readonly goals: GoalSpec[]` |  |
| `reached` | `readonly reached = new Set<string>()` |  |
| `score` | `score = 0` | Current score, as last published. |
| `timeLeft` | `timeLeft: number \| null = null` | Remaining countdown in seconds, or null when no timer is running. |
| `constructor` | `constructor(ctx: Ctx, opts: HudOptions = {})` |  |
| `discoverGoals` | `static discoverGoals(ctx: Ctx): GoalSpec[]` | Every `goal` component in the scene, in contract order. |
| `currentGoal` | `get currentGoal(): GoalSpec \| null` | The lowest-ordered goal not yet reached, or null when they are all done. |
| `total` | `get total(): number` |  |
| `completed` | `get completed(): number` |  |
| `progressText` | `get progressText(): string` | "2/5", the string published to the progress field. |
| `done` | `get done(): boolean` |  |
| `start` | `start(): void` | Publish the current objective and progress. Call once from `init`. |
| `complete` | `complete(goalId: string): boolean` | Mark a goal reached and republish. Returns false when the id is unknown or already reached. SPEC (D4, review H2): an unknown id is no longer dropped in silence. It is looked for once more — the goals may simply not have been discovered yet — and if it is still unknown it is remembered in `pending` and logged, so a mistyped `labelKey` or a `goal-reached` for something that is not a goal shows up in the run's log instead of as a HUD that never moves. |
| `handle` | `handle(ev: GameEvent): boolean` | Handle one delivered event. Returns true when it was a goal event that moved the HUD on, which happens in the same tick the event is delivered. |
| `refresh` | `refresh(): void` | Push the objective and progress for the current state. |
| `objective` | `objective(textKey: string): void` | Set the objective explicitly, outside the goal sequence. |
| `prompt` | `prompt(textKey: string \| null): void` | Show or hide a contextual prompt. |
| `timer` | `timer(seconds: number \| null): void` | Show a countdown without running it. |
| `startTimer` | `startTimer(seconds: number): void` | Start a countdown this controller ticks down in `update`. |
| `stopTimer` | `stopTimer(): void` | Stop and hide a running countdown. |
| `setScore` | `setScore(value: number): void` |  |
| `addScore` | `addScore(delta: number): void` |  |
| `set` | `set(field: HudField, value: string \| number \| null, options?: HudFieldOptions): void` | Any field, built-in or custom. Text values are keys and are checked against the string table. `options`  give the field a label, a unit and fixed decimals (`ctx.hud.set`'s; e.g. `{ unit: "km/h" }`). |
| `update` | `update(dt: number): void` | Tick a running countdown. Emits the timer event once when it reaches zero. |
