@ferret/platform
One interface over OS Beroun and the browser: saved state, suspend, exit, screen size, device class, render scale and quality tiers.
Classes
BerounPlatform class
class BerounPlatform extends DomPlatform implements FerretPlatformOS Beroun: the global Platform object that /platform.js provides.
readonly kind: "beroun" | |
constructor(api: any = (globalThis as any).Platform) | |
async loadState<T>() | Saved state of the game (null when there is none). |
async saveState(state: unknown) | |
exit() | Leave the game: OS Beroun closes the app; a browser goes back to the game's start page. |
async capabilities() | |
log(msg: string) | Plain text to the host's log (the OS Beroun shell's log; the browser console). |
packages/platform/src/platform.ts:67
BrowserPlatform class
class BrowserPlatform extends DomPlatform implements FerretPlatformAn ordinary desktop or mobile browser.
readonly kind: "browser" | |
constructor(private key = 'ferret', private startPage = './') | |
async loadState<T>(): Promise<T | null> | Saved state of the game (null when there is none). |
async saveState(state: unknown) | |
exit() | Leave the game: OS Beroun closes the app; a browser goes back to the game's start page. |
async capabilities() | |
async requestFullscreen() | |
log(msg: string) | Plain text to the host's log (the OS Beroun shell's log; the browser console). |
packages/platform/src/platform.ts:87
Display class
class DisplayKeeps an engine's canvas, hardware scaling, quality and cameras in step with the screen. Resize, rotation, fullscreen and a move to an external screen are handled without reloading anything.
quality: QualitySettings | |
renderScale: number | |
xrActive: boolean | a VR session owns the render target and the field of view: the screen scaling and FOV are left alone while it runs |
onChange?: (d: Display) => void | |
constructor(readonly engine: BABYLON.AbstractEngine, readonly platform: { screen(): ScreenInfo; onResize(fn: (s: ScreenInfo) => void): () => void; kind: string }, opts: { tier?: QualityTier; baseVerticalFov?: number; minHorizontalFov?: number } = {}) | |
setTier(tier: QualityTier) | |
setXr(on: boolean) | Enter or leave VR: the xr tier while a session runs, the screen's tier after. |
trackCamera(cam: BABYLON.Camera) | |
get aspect(): number | |
apply() | |
applyFov() | |
dispose() |
packages/platform/src/display.ts:77
HeadlessPlatform class
class HeadlessPlatform implements FerretPlatformTests: everything in memory, nothing needs a DOM.
readonly kind: "headless" | |
state: unknown | |
exited: boolean | |
logs: string[] | |
size: ScreenInfo | |
async loadState<T>() | Saved state of the game (null when there is none). |
async saveState(s: unknown) | |
onSuspend(fn: (reason: string) => void | Promise<void>) | Called before the page goes away (OS Beroun: the app is closed, ~2 s to save; browser: hidden/closed). |
async suspend(reason = 'closed') | |
exit() | Leave the game: OS Beroun closes the app; a browser goes back to the game's start page. |
async capabilities() | |
screen() | |
onResize(fn: (s: ScreenInfo) => void) | |
resize(w: number, h: number, density = 1, deviceClass?: DeviceClass) | |
log(msg: string) | Plain text to the host's log (the OS Beroun shell's log; the browser console). |
packages/platform/src/platform.ts:135
Functions
classifyDevice function
function classifyDevice(width: number, height: number, kind: PlatformKind, coarse: boolean): DeviceClasspackages/platform/src/platform.ts:37
detectLevelTier function
function detectLevelTier(o: TierOptions = {}): TierChoiceThe level tier for this browser, with the reason (for the log and for a debug line):
- a software renderer, little memory, data saving or a slow network -> low;
- phones and tablets -> mobile;
- a desktop with its own graphics card (NVIDIA, AMD, Apple M, Intel Arc) -> desktop;
- an old integrated card or few cores / little memory -> mobile;
- nothing known -> desktop on a desktop, mobile on a touch device.
The page can still give the player a switch; this is only the first choice.
packages/platform/src/tier.ts:69
detectPlatform function
function detectPlatform(opts: { key?: string; startPage?: string } = {}): FerretPlatformPick the implementation: OS Beroun when /platform.js is present, else the browser.
packages/platform/src/platform.ts:159
fovFor function
function fovFor(aspect: number, baseVertical = 0.9, minHorizontal = 1.0): numberVertical field of view for an aspect ratio: fixed vertical FOV, so the view widens with the aspect; on tall (portrait) screens it grows so that the horizontal FOV does not fall below minHorizontal (the playable view stays the same).
packages/platform/src/display.ts:55
initialTier function
function initialTier(deviceClass: DeviceClass, kind: 'beroun' | 'browser' | 'headless'): QualityTierThe tier chosen from the device class. The console is always low; a benchmark may refine the others later.
packages/platform/src/display.ts:34
probeDevice function
function probeDevice(): DeviceProbeReads the device from the browser. The graphics card is read from a throw-away canvas that is released at once.
packages/platform/src/tier.ts:21
renderScaleFor function
function renderScaleFor(screen: ScreenInfo, tier: QualityTier, requested = 1): numberThe render scale (<= 1) that keeps the frame within the tier's pixel budget.
packages/platform/src/display.ts:45
uiScaleFor function
function uiScaleFor(screen: ScreenInfo): numberUI scale from the screen's physical size, not its pixels: text stays readable on a console and on a phone.
packages/platform/src/display.ts:63
Interfaces
DeviceProbe interface
interface DeviceProbeWhat the browser tells about the machine. Every field is optional: a browser may hide any of them.
renderer?: string | the graphics card (WEBGL_debug_renderer_info): ANGLE (NVIDIA, NVIDIA GeForce RTX 3050 ...) |
memoryGB?: number | navigator.deviceMemory, GB, rounded down to a power of two and capped at 8 |
cores?: number | |
saveData?: boolean | the user asked the browser to save data |
connection?: string | navigator.connection.effectiveType |
packages/platform/src/tier.ts:8
FerretPlatform interface
interface FerretPlatformOne interface, two implementations (plus a headless one for tests). OS Beroun: Platform.state / onClose / exit / capabilities of /platform.js. Browser: IndexedDB/localStorage state, visibilitychange/pagehide as suspend, fullscreen, orientation.
readonly kind: PlatformKind | |
loadState<T = any>(): Promise<T | null> | Saved state of the game (null when there is none). |
saveState(state: unknown): Promise<void> | |
onSuspend(fn: (reason: string) => void | Promise<void>): () => void | Called before the page goes away (OS Beroun: the app is closed, ~2 s to save; browser: hidden/closed). |
exit(): void | Leave the game: OS Beroun closes the app; a browser goes back to the game's start page. |
capabilities(): Promise<string[]> | |
screen(): ScreenInfo | |
onResize(fn: (s: ScreenInfo) => void): () => void | |
requestFullscreen?(): Promise<void> | |
log(msg: string): void | Plain text to the host's log (the OS Beroun shell's log; the browser console). |
packages/platform/src/platform.ts:20
QualitySettings interface
interface QualitySettingstier: QualityTier | |
renderScale: number | 1 = native size x density; lower renders fewer pixels (hardware scaling = 1 / renderScale) |
shadowMapSize: number | |
shadowCascades: number | |
lodBias: number | |
maxTextureSize: number | |
fxaa: boolean | |
msaa: number | |
postProcessing: boolean | |
drawDistance: number | |
foveation?: number | VR: fixed foveation 0..1 (the headset renders the edges of the view at lower resolution) |
framebufferScale?: { min: number; max: number; start: number } | VR: the range the framebuffer scale may move in, and where it starts |
streaming?: { radius: number; budget: number } | VR: scale of the streaming radii and of the per-frame instantiation work |
packages/platform/src/display.ts:5
ScreenInfo interface
interface ScreenInfowidth: number | |
height: number | |
density: number | devicePixelRatio |
portrait: boolean | |
deviceClass: DeviceClass |
packages/platform/src/platform.ts:6
TierChoice interface
interface TierChoicetier: LevelTier | |
reason: string |
packages/platform/src/tier.ts:48
TierOptions interface
interface TierOptionsoverride?: string | null | the tier asked for in the address (?tier=) or in a setting: wins when it is one of the tiers and the level has it |
screen?: Pick<ScreenInfo, 'deviceClass'> | |
probe?: DeviceProbe | default: probeDevice() |
available?: readonly LevelTier[] | the tiers the level package has (default: all three). A tier that is not there gives way to the nearest one. |
packages/platform/src/tier.ts:50
Types
DeviceClass type
type DeviceClass = 'console' | 'phone' | 'tablet' | 'desktop'packages/platform/src/platform.ts:4
LevelTier type
type LevelTier = 'desktop' | 'mobile' | 'low'The quality variants a level package comes in (tiers.json of the exporter): a folder per tier, desktop the richest.
packages/platform/src/tier.ts:4
PlatformKind type
type PlatformKind = 'beroun' | 'browser' | 'headless'packages/platform/src/platform.ts:3
QualityTier type
type QualityTier = 'low' | 'medium' | 'high' | 'xr'packages/platform/src/display.ts:3
Constants
LEVEL_TIERS const
const LEVEL_TIERS: readonly LevelTier[]packages/platform/src/tier.ts:5
QUALITY const
const QUALITY: Record<QualityTier, QualitySettings>packages/platform/src/display.ts:25