/** * The decision "what should the start interaction do on this poll", extracted pure so it is * testable without a browser (the same split `settle.ts` makes). * * Starting a game the way a player does is no longer just "press Play": the engine's pre-play * selection framework (`worldProfileData.hud.startScreen.selections`) can put a level chooser in * front of the world load and further choice steps between the load and Play, and every one of * them HIDES the Play button until an option is picked. A run that only ever looked for Play sat * on the chooser until its timeout and reported a healthy game as one that never started. * * Loading is the other thing that hides Play. The engine un-hides the button only when the world * has finished loading, and a big world (heavy voxel generation, GPU warmup) legitimately takes * longer than the button budget — so a run whose clock started at page load gave up on Play * before the engine could possibly have shown it, and reported a healthy game as one that never * started. While the engine itself reports `gameState === 'loading'`, the budget for Play has * not meaningfully begun; `loadingGraceMs` bounds how long that credit can last. */ export interface StartInteractionOptions { /** Selector for the engine Play button. Its label is localizable and per-game overridable, so * never match by text. */ playButtonSelector: string; /** * Selector for one option of a pre-play selection step (level chooser, difficulty, …), as * built by the engine's `buildSelectionStepElement`. * * The options carry no id, value or data attribute — only their label text — so the first one * is the only stable target. That is also the pick the engine itself takes whenever a flow * skips the step (`defaultPick`), so verify choosing it keeps auto-started and player-started * runs on the same level. */ selectionOptionSelector: string; /** Console line the engine logs when `handleGameStart()` runs — every start path (button * click, auto-starting genres, custom start UIs calling `engine.startGame()`) produces it. */ startedConsoleMarker: string; /** How long the Play button (or an auto-start) gets to show up. Measured from page load, and * restarted on every selection pick — the level pick is what begins the world load, so the * budget means "time to load after the pick" rather than "time since the page appeared". It is * also restarted on every poll that sees the engine still loading (up to `loadingGraceMs`), * so it means "time for Play to appear once the world is loaded", not "time to load". */ buttonTimeoutMs: number; /** How long the engine may keep reporting `gameState === 'loading'` before the run stops * crediting it and lets `buttonTimeoutMs` burn. A runaway guard, not a verdict: a load that * outlasts it still gets one more full button budget after the last credited poll. */ loadingGraceMs: number; /** How long after clicking the button the start marker gets to appear. */ postClickStartTimeoutMs: number; /** Safety cap on how many selection steps one run clicks through. Real games present one level * chooser plus a handful of choice steps; the cap only bounds a game whose steps never end. */ maxSelectionPicks: number; } export declare const DEFAULT_START_INTERACTION: StartInteractionOptions; export declare const START_POLL_MS = 250; /** * Polls Play must have been visible for before it is pressed. * * The engine un-hides Play as soon as the world is loaded and only THEN presents the choice * steps, an async turn later — so there is a window where Play is visible with a step about to * take the screen back. Pressing into that window either force-starts past the steps or, worse, * hits a button that goes `display:none` mid-click. Requiring Play to still be there one poll * later costs 250ms and lets the steps get clicked properly. */ export declare const PLAY_CONFIRM_POLLS = 2; export declare function hasStartMarker(consoleLines: string[], marker: string): boolean; /** What one poll of the start interaction sees. */ export interface StartPollSample { /** The engine's start marker is already in the captured console. */ startMarkerSeen: boolean; /** The Play button is visible right now. */ playButtonVisible: boolean; /** An option of a pre-play selection step is visible right now. */ selectionOptionVisible: boolean; /** Selection options this run has already pressed. */ picksMade: number; /** Consecutive polls (this one included) that have seen Play visible. */ playVisiblePolls: number; /** The engine reports `gameState === 'loading'` right now — the world is still being built, * so Play cannot appear yet. False when the page cannot be asked: "not observed" must never * extend a wait, or a wedged page could hold the run open. */ gameLoading: boolean; /** Milliseconds since the start interaction began, for the `loadingGraceMs` cap. */ elapsedMs: number; } export type StartPollAction = 'started' | 'pick-selection' | 'press-play' | 'wait-loading' | 'keep-waiting'; /** * What to do with this poll. * * A visible selection option outranks a visible Play button: a mounted step means the engine is * about to hide Play, so pressing it would only time out — and the step is the thing standing * between the run and gameplay. Anything actually on screen outranks a `loading` report: what is * pressable now is the ground truth, whatever state the engine claims to be in. */ export declare function startPollAction(sample: StartPollSample, options: StartInteractionOptions): StartPollAction;