# ready and gameplay

sdk.ready() hides the host's loader; sdk.gameplay.start() and stop() bracket real play; sdk.happyTime() marks a win.

Four void calls. They return nothing and never throw after `init()`; called while `init()` is pending they
wait for it.

## `ready(): void`

Call it when the game can be seen and played, once the first frame is drawn. It forwards to the host's
loading-stop: filudi.com hides its loader, CrazyGames gets `loadingStop`, Poki `gameLoadingFinished`.
Idempotent: a second call does nothing.

<CodePanel title="Ready after the first frame">
  <Fragment slot="javascript">
    ```js
    let first = true;

    function frame(now) {
      draw(now);
      if (first) {
        first = false;
        sdk.ready();
      }
      requestAnimationFrame(frame);
    }
    ```

  </Fragment>
  <Fragment slot="typescript">
    ```ts
    let first = true;

    function frame(now: DOMHighResTimeStamp): void {
      draw(now);
      if (first) {
        first = false;
        sdk.ready();
      }
      requestAnimationFrame(frame);
    }
    ```

  </Fragment>
</CodePanel>

## `gameplay.start(): void` and `gameplay.stop(): void`

Bracket real play. Not menus, not loading, not an ad. The SDK dedupes: two `start()` in a row send one, so
drop the game's own `playing` flag. The SDK itself calls `stop()` before an ad and `start()` after it when
play was running: never call them around an ad yourself.

On filudi.com `start()` opens a play session and receives the key that signs scores. A score submitted
outside a session is rejected, see [leaderboard](/docs/sdk/leaderboard/).

<CodePanel title="Bracket play">
  <Fragment slot="javascript">
    ```js
    function startRun() {
      state.mode = 'run';
      sdk.gameplay.start();
    }

    function endRun() {
      state.mode = 'over';
      sdk.gameplay.stop();
    }

    pauseButton.addEventListener('click', () => {
      state.mode = 'paused';
      sdk.gameplay.stop();
    });
    ```

  </Fragment>
  <Fragment slot="typescript">
    ```ts
    type Mode = 'menu' | 'run' | 'paused' | 'over';

    function setMode(mode: Mode): void {
      state.mode = mode;
      if (mode === 'run') sdk.gameplay.start();
      else sdk.gameplay.stop();
    }
    ```

  </Fragment>
</CodePanel>

## `happyTime(): void`

A win or a level clear. Hosts that have the concept (CrazyGames `happytime`) get it; the others ignore it.

<CodePanel title="Celebrate a level clear">
  <Fragment slot="javascript">
    ```js
    function levelCleared() {
      sdk.gameplay.stop();
      sdk.happyTime();
      showSummary();
    }
    ```

  </Fragment>
  <Fragment slot="typescript">
    ```ts
    function levelCleared(): void {
      sdk.gameplay.stop();
      sdk.happyTime();
      showSummary();
    }
    ```

  </Fragment>
</CodePanel>

## Unavailable cases

None. On a host without the concept the call is a no-op. On filudi.com `ready()` posts `filudi:loaded` and
`gameplay` posts `filudi:gameplay { running }`; the hub counts the first as the first step of your funnel
and the second as a session, see [events and statistics](/docs/games/events-and-statistics/).
