# Platform and display

# Platform and display

Games never talk to OS Beroun or to the page directly. They use `FerretPlatform`, which has three implementations and picks one with `detectPlatform`:

| Implementation | When | Notes |
|---|---|---|
| `BerounPlatform` | `/platform.js` is present (OS Beroun) | state in the OS, log to the shell, `exit()` closes the app |
| `BrowserPlatform` | any other page | state in `localStorage` under the game's `storageKey`, fullscreen, `exit()` goes back to the start page |
| `HeadlessPlatform` | tests | everything in memory; `resize()` and `suspend()` to simulate the host |

## What the interface gives

- **Saved state**: `loadState()` returns what the game saved last (or `null`), `saveState(obj)` stores it.
- **Suspend**: `onSuspend(fn)` is called before the page goes away. On OS Beroun the app is closed and has about two seconds to save; in a browser the tab is hidden or closed. Save there.
- **Exit**: `exit()`.
- **Screen**: `screen()` returns size, pixel density and the `DeviceClass` (`console`, `phone`, `tablet`, `desktop`); `onResize(fn)` follows it.
- **Log**: `log(msg)`.

## Display and quality

`Display` keeps the canvas, the hardware scaling factor, the quality settings and cameras in step with the screen. A phone held upright and a 4K monitor use the same game: `trackCamera(cam)` sets the field of view from the aspect (a fixed vertical angle that widens on wide screens, with a minimum horizontal angle so tall screens still see enough, see `fovFor`), and `renderScale` trades sharpness for speed.

`initialTier` chooses the starting quality tier from the device class; the console is always `low`. `display.setTier(tier)` changes it at run time. The physics budget has tiers of its own that follow the same names, see Physics overview (skill `ferret`).

## Writing for all of them

- Bind actions, never keys: the console has a cursor, A and B, no mouse look and no Pointer Lock (Input and UI (skill `ferret-input-ui`)).
- Lay the HUD out in `em` from the UI scale, not in pixels.
- Save on `onSuspend`; do not rely on `beforeunload`.
- Keep the first frame small: assets are streamed and loaded after the loading screen is up (Levels (skill `ferret-levels`)).
