js-game-zero 0.0.0-stage → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +138 -2
  3. package/dist/active-service.d.ts +21 -0
  4. package/dist/actor.d.ts +182 -0
  5. package/dist/animation.d.ts +61 -0
  6. package/dist/assets.d.ts +148 -0
  7. package/dist/audio.d.ts +150 -0
  8. package/dist/browser-asset-backends.d.ts +8 -0
  9. package/dist/browser.d.ts +10 -0
  10. package/dist/chunk-q9m20c2h.js +7972 -0
  11. package/dist/clock.d.ts +29 -0
  12. package/dist/color.d.ts +15 -0
  13. package/dist/events.d.ts +145 -0
  14. package/dist/friendly-names.d.ts +43 -0
  15. package/dist/geometry.d.ts +125 -0
  16. package/dist/helpers.d.ts +28 -0
  17. package/dist/host.d.ts +58 -0
  18. package/dist/host.js +435 -0
  19. package/dist/index.d.ts +340 -0
  20. package/dist/index.js +258 -0
  21. package/dist/input.d.ts +200 -0
  22. package/dist/inspection.d.ts +58 -0
  23. package/dist/jgz.js +8545 -0
  24. package/dist/node.d.ts +14 -0
  25. package/dist/node.js +145 -0
  26. package/dist/pixel-density.d.ts +23 -0
  27. package/dist/random.d.ts +31 -0
  28. package/dist/reference/actor.md +197 -0
  29. package/dist/reference/audio.md +128 -0
  30. package/dist/reference/clock.md +150 -0
  31. package/dist/reference/helpers.md +46 -0
  32. package/dist/reference/hooks.md +379 -0
  33. package/dist/reference/index.d.ts +2 -0
  34. package/dist/reference/index.js +39 -0
  35. package/dist/reference/loaders.md +164 -0
  36. package/dist/reference/rect.md +129 -0
  37. package/dist/reference/runtime.md +478 -0
  38. package/dist/reference/screen.md +392 -0
  39. package/dist/reference/storage.md +90 -0
  40. package/dist/rendering.d.ts +216 -0
  41. package/dist/runtime-contracts.d.ts +117 -0
  42. package/dist/runtime-diagnostics.d.ts +37 -0
  43. package/dist/runtime-persistence.d.ts +32 -0
  44. package/dist/runtime-source.d.ts +82 -0
  45. package/dist/runtime.d.ts +81 -0
  46. package/dist/source-scan.d.ts +49 -0
  47. package/dist/storage-path.d.ts +3 -0
  48. package/dist/storage.d.ts +88 -0
  49. package/dist/tone.d.ts +81 -0
  50. package/dist/touch-controls.d.ts +24 -0
  51. package/dist/touch-pointer.d.ts +11 -0
  52. package/dist/util.d.ts +62 -0
  53. package/package.json +69 -4
@@ -0,0 +1,216 @@
1
+ import { type AssetLoader, type SurfaceLike } from "./assets.js";
2
+ import { type Color } from "./color.js";
3
+ import { ZRect, type Point, type RectLike } from "./geometry.js";
4
+ export { normalizeColor } from "./color.js";
5
+ export type { Color } from "./color.js";
6
+ export type CanvasLike = {
7
+ readonly width: number;
8
+ readonly height: number;
9
+ getContext?: (contextId: "2d") => CanvasRenderingContext2D | null;
10
+ };
11
+ export type ScreenOptions = {
12
+ readonly imageLoader?: Pick<AssetLoader<SurfaceLike>, "load" | "get">;
13
+ };
14
+ export type TextAlignOption = "left" | "center" | "right";
15
+ export type TextAnchor = "topLeft" | "topRight" | "bottomLeft" | "bottomRight" | "midTop" | "midLeft" | "midRight" | "midBottom" | "center" | readonly [number | HorizontalAnchor, number | VerticalAnchor];
16
+ export type HorizontalAnchor = "left" | "center" | "middle" | "right";
17
+ export type VerticalAnchor = "top" | "center" | "middle" | "bottom";
18
+ export type TextOptions = {
19
+ readonly fontname?: string;
20
+ readonly sysfontname?: string;
21
+ readonly fontsize?: number;
22
+ /** Same as `fontsize`. */
23
+ readonly size?: number;
24
+ readonly bold?: boolean;
25
+ readonly italic?: boolean;
26
+ readonly underline?: boolean;
27
+ readonly color?: Color;
28
+ readonly background?: Color;
29
+ readonly pos?: Point;
30
+ readonly topLeft?: Point;
31
+ readonly topRight?: Point;
32
+ readonly bottomLeft?: Point;
33
+ readonly bottomRight?: Point;
34
+ readonly midTop?: Point;
35
+ readonly midLeft?: Point;
36
+ readonly midRight?: Point;
37
+ readonly midBottom?: Point;
38
+ readonly center?: Point;
39
+ readonly top?: number;
40
+ readonly left?: number;
41
+ readonly bottom?: number;
42
+ readonly right?: number;
43
+ readonly centerX?: number;
44
+ readonly centerY?: number;
45
+ readonly width?: number;
46
+ readonly widthem?: number;
47
+ readonly lineheight?: number;
48
+ readonly align?: TextAlignOption;
49
+ readonly strip?: boolean;
50
+ readonly owidth?: number;
51
+ /** Same as `owidth`. */
52
+ readonly outline?: number;
53
+ readonly ocolor?: Color;
54
+ /** Same as `ocolor`. */
55
+ readonly outlineColor?: Color;
56
+ readonly shadow?: number | Point;
57
+ readonly scolor?: Color;
58
+ /** Same as `scolor`. */
59
+ readonly shadowColor?: Color;
60
+ readonly gcolor?: Color;
61
+ /** Same as `gcolor`. */
62
+ readonly gradientColor?: Color;
63
+ readonly alpha?: number;
64
+ readonly anchor?: TextAnchor;
65
+ readonly angle?: number;
66
+ };
67
+ export type TextboxOptions = Omit<TextOptions, TextPositionKey | "width" | "widthem" | "top" | "left" | "bottom" | "right" | "centerX" | "centerY"> & {
68
+ readonly minFontsize?: number;
69
+ /** Same as `minFontsize`. */
70
+ readonly minSize?: number;
71
+ };
72
+ /**
73
+ * `screen.draw.text` takes its options either third, after a position, or
74
+ * second, in place of one: `text("Hi", [10, 10], { size: 20 })` and
75
+ * `text("Hi", { center: [160, 90], size: 20 })` both work.
76
+ */
77
+ export type DrawText = {
78
+ (text: string, options?: TextOptions): void;
79
+ (text: string, pos: Point | undefined, options?: TextOptions): void;
80
+ };
81
+ /** How big `screen.measureText` finds text, as `screen.draw.text` would draw it. */
82
+ export type TextSize = {
83
+ /** Its widest line's width. */
84
+ readonly width: number;
85
+ /** Its lines' height together: as many lines as it has, each `lineheight` tall. */
86
+ readonly height: number;
87
+ /** The lines it breaks into: at each newline, and where a `width` wraps it. */
88
+ readonly lines: readonly string[];
89
+ };
90
+ export type TextLayout = {
91
+ readonly lines: readonly string[];
92
+ readonly font: string;
93
+ readonly fontSize: number;
94
+ readonly lineHeight: number;
95
+ readonly boxWidth: number;
96
+ readonly boxHeight: number;
97
+ readonly textWidth: number;
98
+ readonly align: TextAlignOption;
99
+ readonly topLeft: Point;
100
+ readonly anchorOffset: Point;
101
+ readonly alpha: number;
102
+ };
103
+ type TextPositionKey = "pos" | "topLeft" | "topRight" | "bottomLeft" | "bottomRight" | "midTop" | "midLeft" | "midRight" | "midBottom" | "center";
104
+ /**
105
+ * Sizes the screen to `width` × `height` logical pixels with `density`
106
+ * canvas pixels each, and scales the context so every drawing call keeps
107
+ * working in logical pixels. A density change keeps what's on the canvas,
108
+ * rescaled; a new size starts blank, as setting a canvas's size does.
109
+ */
110
+ export declare function resizeScreen(screen: Screen, width: number, height: number, density?: number): void;
111
+ /**
112
+ * Restores the density scale if something reset the canvas since the last
113
+ * frame. Code outside the runtime that sets `canvas.width`/`height` means
114
+ * a logical size, so the screen adopts it at the same density.
115
+ */
116
+ export declare function syncScreen(screen: Screen): void;
117
+ /** A value a drawn thing reports, as JSON. */
118
+ type DrawnValue = string | number | boolean | readonly number[];
119
+ /**
120
+ * One thing a frame drew, as a host reads it through the inspector's
121
+ * `$drawn`: its kind (`fill`, `image`, `actor`, `circle`, `rect`, `polygon`,
122
+ * `line`, `text`, `clear`), and what it is and where, as the game gave them.
123
+ */
124
+ export type DrawnThing = {
125
+ readonly kind: string;
126
+ readonly [key: string]: DrawnValue;
127
+ };
128
+ /** Starts recording what `screen` draws, afresh: the runtime calls it before each `draw()`. */
129
+ export declare function beginDrawn(screen: Screen): void;
130
+ /** What `screen`'s last `draw()` drew, in order; empty before its first. */
131
+ export declare function drawnOn(screen: Screen): readonly DrawnThing[];
132
+ /** Records one thing drawn, when the screen is recording. */
133
+ export declare function recordDrawn(screen: Screen, thing: DrawnThing): void;
134
+ export declare class Screen {
135
+ readonly canvas: CanvasLike;
136
+ readonly context: CanvasRenderingContext2D;
137
+ readonly imageLoader: Pick<AssetLoader<SurfaceLike>, "load" | "get">;
138
+ readonly draw: {
139
+ line: (start: Point, end: Point, color: Color, width?: number) => void;
140
+ circle: (pos: Point, radius: number, color: Color, width?: number) => void;
141
+ filledCircle: (pos: Point, radius: number, color: Color) => void;
142
+ polygon: (points: Point[], color: Color, width?: number) => void;
143
+ filledPolygon: (points: Point[], color: Color) => void;
144
+ rect: (rect: RectLike, color: Color, width?: number) => void;
145
+ filledRect: (rect: RectLike, color: Color) => void;
146
+ /** Its corners are rounded `radius` round, at most half its shorter side. */
147
+ roundedRect: (rect: RectLike, radius: number, color: Color, width?: number) => void;
148
+ filledRoundedRect: (rect: RectLike, radius: number, color: Color) => void;
149
+ text: DrawText;
150
+ textbox: (text: string, rect: RectLike, options?: TextboxOptions) => void;
151
+ /** Same as `screen.blit`: draws an image with its top-left at `pos`. */
152
+ image: (image: string | SurfaceLike, pos: Point | RectLike) => Promise<void> | void;
153
+ };
154
+ constructor(canvas: CanvasLike, context?: CanvasRenderingContext2D | null, options?: ScreenOptions);
155
+ /** The screen's width in logical pixels: the game's `WIDTH`. */
156
+ get width(): number;
157
+ /** The screen's height in logical pixels: the game's `HEIGHT`. */
158
+ get height(): number;
159
+ /** Canvas pixels per logical pixel along each side. */
160
+ get density(): number;
161
+ bounds(): ZRect;
162
+ clear(): void;
163
+ fill(color: Color, gcolor?: Color): void;
164
+ blit(image: string | SurfaceLike, pos: Point | RectLike): Promise<void> | void;
165
+ /**
166
+ * The short forms take positions as separate numbers rather than `[x, y]`
167
+ * lists, fill their shapes, and default to white, so
168
+ * `screen.circle(200, 150, 25, "gold")` fits a phone-width line where
169
+ * `screen.draw.filledCircle([200, 150], 25, "gold")` doesn't. The
170
+ * outline versions stay under `screen.draw`.
171
+ */
172
+ circle(x: number, y: number, radius: number, color?: Color): void;
173
+ /** A filled rectangle whose top-left corner is at `x, y`. */
174
+ rect(x: number, y: number, width: number, height: number, color?: Color): void;
175
+ /**
176
+ * A filled rectangle like `screen.rect`'s, with its corners rounded
177
+ * `radius` round. The radius comes before the color, as a circle's does.
178
+ */
179
+ roundedRect(x: number, y: number, width: number, height: number, radius: number, color?: Color): void;
180
+ triangle(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, color?: Color): void;
181
+ line(x1: number, y1: number, x2: number, y2: number, color?: Color, width?: number): void;
182
+ /**
183
+ * Text whose top-left corner is at `x, y`, `size` pixels tall, so a score
184
+ * fits one short line: `screen.text("Score: " + score, 20, 30)`. A number
185
+ * is drawn as it reads. Placing by its center or any other option stays
186
+ * under `screen.draw.text`.
187
+ */
188
+ text(text: string | number, x: number, y: number, color?: Color, size?: number): void;
189
+ /**
190
+ * How big `screen.draw.text` would draw `text`, measured the way it lays
191
+ * it out: its widest line's width, its lines' height together, and the
192
+ * lines. It takes what `screen.draw.text` takes, so a label is measured
193
+ * with the arguments it's drawn with; where it goes doesn't change its
194
+ * size. It draws nothing.
195
+ */
196
+ measureText(text: string | number, options?: TextOptions): TextSize;
197
+ measureText(text: string | number, pos: Point | undefined, options?: TextOptions): TextSize;
198
+ private drawSurface;
199
+ private drawLine;
200
+ private drawCircle;
201
+ private drawPolygon;
202
+ private drawRect;
203
+ /** `call` is how the method that drew it is called, for its errors. */
204
+ private drawRoundedRect;
205
+ private drawText;
206
+ private drawTextbox;
207
+ }
208
+ export declare function setScreen(screen: Screen | null): Screen | null;
209
+ export declare function getScreen(): Screen;
210
+ export declare const screen: Screen;
211
+ export declare function layoutText(context: CanvasRenderingContext2D, text: string, pos: Point | undefined, options?: TextOptions): TextLayout;
212
+ export declare function fitTextboxFontSize(context: CanvasRenderingContext2D, text: string, rectLike: RectLike, options?: TextboxOptions): {
213
+ fontSize: number;
214
+ lineHeight: number;
215
+ lines: readonly string[];
216
+ };
@@ -0,0 +1,117 @@
1
+ import type { AssetLoaders, AssetUrls, FontAsset, MusicAsset, SoundAsset, SurfaceLike } from "./assets.js";
2
+ import type { InputHooks, MappedKeyboardEvent, MappedMouseEvent } from "./events.js";
3
+ import type { Storage, StorageAdapter } from "./storage.js";
4
+ import type { TouchControlsConfig } from "./touch-controls.js";
5
+ export type GameModule = InputHooks & {
6
+ readonly WIDTH?: number;
7
+ readonly HEIGHT?: number;
8
+ /**
9
+ * Canvas pixels per logical pixel. Defaults to the device's pixel ratio,
10
+ * at most 3, so the game is sharp on high-density screens.
11
+ */
12
+ readonly PIXEL_DENSITY?: number;
13
+ readonly TITLE?: string;
14
+ readonly ICON?: string | null;
15
+ readonly TOUCH_CONTROLS?: TouchControlsConfig;
16
+ readonly draw?: () => void;
17
+ /** Called every frame with the seconds since the last one. */
18
+ readonly update?: (dt: number) => void;
19
+ };
20
+ export type RuntimeMode = "global" | "import";
21
+ export type RuntimeDiagnostic = {
22
+ readonly code: "asset-name" | "constant-typo" | "duplicate-config" | "hook-arity" | "hook-parameter" | "hook-typo" | "invalid-config" | "runtime-error";
23
+ readonly severity: "warning" | "error";
24
+ readonly message: string;
25
+ readonly name?: string;
26
+ readonly suggestion?: string;
27
+ readonly phase?: RuntimeFailurePhase;
28
+ /**
29
+ * The 1-based line in the game source the diagnostic is about, when known:
30
+ * where a `runtime-error` was thrown, or where a misspelled hook or
31
+ * setting is declared.
32
+ */
33
+ readonly line?: number;
34
+ readonly recoverable?: boolean;
35
+ };
36
+ export type RuntimeFailurePhase = "startup" | "input" | "clock" | "update" | "draw" | "asset" | "storage" | "audio";
37
+ export type RuntimeFailure = {
38
+ readonly phase: RuntimeFailurePhase;
39
+ readonly message: string;
40
+ readonly cause: unknown;
41
+ /** 1-based line in the game source where the error was thrown, when the engine reports one. */
42
+ readonly line?: number;
43
+ };
44
+ export type GameHandleState = "starting" | "running" | "paused" | "failed" | "stopped";
45
+ export type RuntimeScheduler = {
46
+ requestAnimationFrame(callback: (timestamp: number) => void): unknown;
47
+ cancelAnimationFrame(handle: unknown): void;
48
+ now?(): number;
49
+ };
50
+ export type RuntimeCanvas = HTMLCanvasElement & {
51
+ getBoundingClientRect?: () => {
52
+ left: number;
53
+ top: number;
54
+ width?: number;
55
+ height?: number;
56
+ };
57
+ };
58
+ export type RunOptions = Partial<GameModule> & {
59
+ readonly assetBaseUrl?: string;
60
+ /**
61
+ * The game's assets by path (`images/cat.svg`), each with its URL, such as
62
+ * a data URL. When set, assets load only from here, never from
63
+ * `assetBaseUrl`, so a page can run a game with no server.
64
+ */
65
+ readonly assetUrls?: AssetUrls;
66
+ readonly autostart?: boolean;
67
+ readonly canvas?: RuntimeCanvas;
68
+ readonly container?: HTMLElement;
69
+ readonly diagnostics?: (diagnostic: RuntimeDiagnostic) => void;
70
+ readonly keyboardTarget?: EventTarget;
71
+ /**
72
+ * Where mouse releases (`mouseup`) are heard. Defaults to `window`, so a
73
+ * drag released outside the canvas still ends; a host running a game it
74
+ * drives itself passes the canvas, so its synthetic releases reach no
75
+ * other game on the page.
76
+ */
77
+ readonly mouseReleaseTarget?: EventTarget;
78
+ readonly preload?: readonly string[];
79
+ readonly preloadedAssets?: PreloadedAssets;
80
+ readonly projectId?: string;
81
+ readonly scheduler?: RuntimeScheduler;
82
+ /**
83
+ * Makes the game's randomness repeatable: `Math.random` as a zero-boilerplate
84
+ * game sees it, and `randomInt` and `randomChoice`, follow one sequence for
85
+ * this seed, the same one `jgz test --seed` uses. Only this game's: the
86
+ * page's `Math.random` and other games are untouched. Up to nine plain
87
+ * digits are the number they spell; anything else is hashed.
88
+ */
89
+ readonly seed?: string | number;
90
+ readonly storage?: Storage | StorageAdapter;
91
+ /** Context-owned loader overrides for embedding hosts and deterministic tests. */
92
+ readonly loaders?: Partial<AssetLoaders>;
93
+ };
94
+ export type PreloadedAssets = {
95
+ readonly images?: Record<string, SurfaceLike>;
96
+ readonly sounds?: Record<string, SoundAsset>;
97
+ readonly music?: Record<string, MusicAsset>;
98
+ readonly fonts?: Record<string, FontAsset>;
99
+ };
100
+ export type GameKeyEvent = Readonly<MappedKeyboardEvent>;
101
+ export type GameMouseEvent = Readonly<MappedMouseEvent>;
102
+ export type DefinedGameModule = {
103
+ readonly WIDTH?: number;
104
+ readonly HEIGHT?: number;
105
+ readonly PIXEL_DENSITY?: number;
106
+ readonly TITLE?: string;
107
+ readonly ICON?: string | null;
108
+ readonly TOUCH_CONTROLS?: TouchControlsConfig;
109
+ readonly draw?: () => void;
110
+ readonly update?: (dt: number) => void;
111
+ readonly onKeyDown?: (event: GameKeyEvent) => void;
112
+ readonly onKeyUp?: (event: GameKeyEvent) => void;
113
+ readonly onMouseDown?: (event: GameMouseEvent) => void;
114
+ readonly onMouseUp?: (event: GameMouseEvent) => void;
115
+ readonly onMouseMove?: (event: GameMouseEvent) => void;
116
+ readonly onMusicEnd?: () => void;
117
+ };
@@ -0,0 +1,37 @@
1
+ import type { GameModule, RunOptions, RuntimeDiagnostic, RuntimeMode } from "./runtime-contracts.js";
2
+ export declare const RUNTIME_CONFIGURATION_NAMES: readonly ["WIDTH", "HEIGHT", "PIXEL_DENSITY", "TITLE", "ICON", "TOUCH_CONTROLS"];
3
+ /** Every hook a zero-boilerplate script can define. */
4
+ export declare const RUNTIME_SOURCE_HOOK_NAMES: readonly ["draw", "update", "onMouseDown", "onMouseUp", "onMouseMove", "onKeyDown", "onKeyUp", "onMusicEnd"];
5
+ export declare const RUNTIME_MODULE_OPTION_NAMES: readonly ["WIDTH", "HEIGHT", "PIXEL_DENSITY", "TITLE", "ICON", "TOUCH_CONTROLS", "draw", "update", "onMouseDown", "onMouseUp", "onMouseMove", "onKeyDown", "onKeyUp", "onMusicEnd"];
6
+ export declare function collectRuntimeDiagnostics(moduleOrSource: GameModule | string, options?: RunOptions): RuntimeDiagnostic[];
7
+ export declare function diagnoseGameModule(module: GameModule, options: RunOptions, emit: (diagnostic: RuntimeDiagnostic) => void, mode: RuntimeMode,
8
+ /** run() stops a game whose draw() takes parameters, and says so: a
9
+ * warning as well would be the same mistake twice. */
10
+ drawArityIsFatal?: boolean): void;
11
+ /**
12
+ * Static checks on zero-boilerplate source. Typo checks only look at what the
13
+ * script defines at top level — a top-level function whose name is nearly a
14
+ * hook name, or a top-level assignment whose name is nearly a configuration
15
+ * constant — never at identifiers the script merely uses (`row`, `col`,
16
+ * `rows[y]`), and never when the real name is also defined (`draw` plus a
17
+ * `drawn` helper is not a typo). Asset-name checks scan every quoted string.
18
+ */
19
+ export declare function diagnoseSource(source: string, emit: (diagnostic: RuntimeDiagnostic) => void): void;
20
+ /**
21
+ * The 1-based line where a game's source declares `name` at the start of a
22
+ * line: `function name(`, `name = ` or `let name = `.
23
+ */
24
+ export declare function declarationLine(source: string, name: string): number | undefined;
25
+ export declare function createDiagnosticEmitter(diagnostics: RuntimeDiagnostic[], callback?: (diagnostic: RuntimeDiagnostic) => void): (diagnostic: RuntimeDiagnostic) => void;
26
+ /**
27
+ * Ambient diagnostic sink for whichever run is active at call time, mirroring
28
+ * the active-service pattern used for loaders/storage/clock. Only valid for
29
+ * the duration of the synchronous call that reads it — callers whose work
30
+ * continues asynchronously (e.g. a loader promise that may reject later)
31
+ * must capture the returned function and close over it rather than reading
32
+ * the ambient value again once the run may have moved on.
33
+ */
34
+ export declare function setActiveDiagnosticEmit(emit: ((diagnostic: RuntimeDiagnostic) => void) | null): ((diagnostic: RuntimeDiagnostic) => void) | null;
35
+ export declare function getActiveDiagnosticEmit(): ((diagnostic: RuntimeDiagnostic) => void) | null;
36
+ export declare function describeRuntimeError(error: unknown): string;
37
+ export declare function isValidRuntimeDimension(value: unknown): value is number;
@@ -0,0 +1,32 @@
1
+ import { Storage } from "./storage.js";
2
+ type PersistenceDiagnostic = {
3
+ readonly code: "runtime-error";
4
+ readonly severity: "warning";
5
+ readonly phase: "storage";
6
+ readonly recoverable: true;
7
+ readonly message: string;
8
+ };
9
+ type PersistenceDiagnosticEmitter = (diagnostic: PersistenceDiagnostic) => void;
10
+ export type Autosave = {
11
+ /**
12
+ * Cancels any pending debounce timer and saves immediately, if anything
13
+ * changed since the last save or load, inside stored objects and lists too.
14
+ */
15
+ flush(): Promise<void>;
16
+ /** Unsubscribes from storage changes and browser lifecycle events. */
17
+ detach(): void;
18
+ };
19
+ /**
20
+ * Coordinates debounced and lifecycle-triggered persistence for one runtime.
21
+ * Writes are serialized and mutations that arrive while a save is active are
22
+ * folded into a subsequent write.
23
+ */
24
+ export declare function attachAutosave(storage: Storage, emit: PersistenceDiagnosticEmitter): Autosave;
25
+ /** Loads exactly once, preferring an adapter's truly synchronous path. */
26
+ export declare function primeStorage(storage: Storage, emit: PersistenceDiagnosticEmitter): {
27
+ state: {
28
+ current: boolean;
29
+ };
30
+ promise: Promise<void>;
31
+ };
32
+ export {};
@@ -0,0 +1,82 @@
1
+ import type { AssetLoaders } from "./assets.js";
2
+ import type { MusicPlayer } from "./audio.js";
3
+ import { Clock } from "./clock.js";
4
+ import { type KeyboardState, type MouseState } from "./input.js";
5
+ import { type RandomSource } from "./random.js";
6
+ import { Screen } from "./rendering.js";
7
+ import type { GameModule, RuntimeDiagnostic } from "./runtime-contracts.js";
8
+ import { Storage } from "./storage.js";
9
+ import type { ToneGenerator } from "./tone.js";
10
+ export type SourceEvaluationContext = {
11
+ readonly screen: Screen;
12
+ readonly clock: Clock;
13
+ readonly keyboard: KeyboardState;
14
+ readonly mouseState: MouseState;
15
+ readonly loaders: AssetLoaders;
16
+ readonly music: MusicPlayer;
17
+ readonly storage: Storage;
18
+ readonly tone: ToneGenerator;
19
+ /** The run's seeded random source, or null to leave `Math` as it is. */
20
+ readonly random: RandomSource | null;
21
+ stop: (() => void) | null;
22
+ };
23
+ export type SourceInspector = {
24
+ /** Non-function top-level declarations and assignments. */
25
+ bindings(): readonly string[];
26
+ /** Top-level function declarations and function-valued bindings. */
27
+ functions(): readonly string[];
28
+ read(name: string): unknown;
29
+ };
30
+ type SourceEvaluation = {
31
+ readonly module: GameModule;
32
+ readonly inspector: SourceInspector;
33
+ };
34
+ /** Evaluates one zero-boilerplate script inside its run-owned service scope. */
35
+ export declare function executeZeroBoilerplateSource(source: string, context: SourceEvaluationContext, emit: (diagnostic: RuntimeDiagnostic) => void): SourceEvaluation;
36
+ /**
37
+ * The one line of `source` that reads `name` (outside strings and comments,
38
+ * and not as a property after a dot), or undefined when it's on none or on
39
+ * more than one.
40
+ */
41
+ export declare function onlyLineOf(name: string, source: string): number | undefined;
42
+ /**
43
+ * How this engine numbers lines in `new Function` code: from the place of a
44
+ * stack frame (V8, SpiderMonkey), or, where a frame there has no location
45
+ * (JavaScriptCore), from the error's own `line`.
46
+ */
47
+ export type FrameCalibration = {
48
+ readonly kind: "stack";
49
+ readonly marker: string;
50
+ readonly offset: number;
51
+ } | {
52
+ readonly kind: "line";
53
+ readonly offset: number;
54
+ /** The `sourceURL` errors from game code carry: none, on JavaScriptCore. */
55
+ readonly url: string | undefined;
56
+ };
57
+ /**
58
+ * The calibration a throw from the first line of game source gives. The
59
+ * throwing frame is the stack's first frame, after V8's `Error: message` line:
60
+ * when it has a location, its place marks game frames; when it has none
61
+ * (JavaScriptCore's `anonymous@`), the error's own `line` is used instead.
62
+ */
63
+ export declare function readCalibration(error: unknown): FrameCalibration | null;
64
+ /** The game source's line for `error` under `calibration`, or undefined when it wasn't thrown there. */
65
+ export declare function lineWith(calibration: FrameCalibration, error: unknown): number | undefined;
66
+ /**
67
+ * The 1-based line of the syntax error `message` in `source`, for engines that
68
+ * give none: the first line whose prefix of the source fails with the same
69
+ * message. An error at the end of the source (something left open) is placed
70
+ * on the line after the last prefix that compiles, where the open part starts.
71
+ */
72
+ export declare function syntaxErrorLine(source: string, message: string): number | undefined;
73
+ /** Records the source line of a mistake the runtime itself finds in a
74
+ * game, which no stack trace could place. */
75
+ export declare function noteSourceLine(error: object, line: number): void;
76
+ /**
77
+ * The 1-based line in the game source where `error` was thrown, or undefined
78
+ * when it wasn't thrown in game code (the error came from the library, or the
79
+ * engine gives no usable position).
80
+ */
81
+ export declare function sourceLineOf(error: unknown): number | undefined;
82
+ export {};
@@ -0,0 +1,81 @@
1
+ import { Actor } from "./actor.js";
2
+ import { Animation, animate } from "./animation.js";
3
+ import { type AssetLoaders } from "./assets.js";
4
+ import { Clock } from "./clock.js";
5
+ import { Rect, ZRect } from "./geometry.js";
6
+ import { KeyboardState, keymods, keys, type LiveMouse } from "./input.js";
7
+ import { createMusicPlayer } from "./audio.js";
8
+ import { Screen } from "./rendering.js";
9
+ import { Storage } from "./storage.js";
10
+ import { createToneGenerator } from "./tone.js";
11
+ import { type SourceInspector } from "./runtime-source.js";
12
+ import type { DefinedGameModule, GameHandleState, GameModule, RunOptions, RuntimeCanvas, RuntimeDiagnostic, RuntimeFailure, RuntimeMode } from "./runtime-contracts.js";
13
+ export type { DefinedGameModule, GameHandleState, GameKeyEvent, GameModule, GameMouseEvent, PreloadedAssets, RunOptions, RuntimeCanvas, RuntimeDiagnostic, RuntimeFailure, RuntimeFailurePhase, RuntimeMode, RuntimeScheduler, } from "./runtime-contracts.js";
14
+ export { collectRuntimeDiagnostics } from "./runtime-diagnostics.js";
15
+ export type GameContext = {
16
+ readonly Actor: typeof Actor;
17
+ readonly Animation: typeof Animation;
18
+ readonly Rect: typeof Rect;
19
+ readonly ZRect: typeof ZRect;
20
+ readonly Screen: typeof Screen;
21
+ readonly Storage: typeof Storage;
22
+ readonly screen: Screen;
23
+ readonly clock: Clock;
24
+ readonly keyboard: KeyboardState;
25
+ readonly keymods: typeof keymods;
26
+ readonly keys: typeof keys;
27
+ readonly mouse: LiveMouse;
28
+ readonly images: AssetLoaders["images"];
29
+ readonly sounds: AssetLoaders["sounds"];
30
+ readonly music: ReturnType<typeof createMusicPlayer>;
31
+ readonly fonts: AssetLoaders["fonts"];
32
+ readonly storage: Storage;
33
+ readonly tone: ReturnType<typeof createToneGenerator>;
34
+ readonly animate: typeof animate;
35
+ readonly exit: typeof exit;
36
+ };
37
+ declare const definedGameBrand: unique symbol;
38
+ export type DefinedGame = {
39
+ readonly [definedGameBrand]: true;
40
+ readonly create: (context: GameContext) => DefinedGameModule;
41
+ };
42
+ export declare function defineGame(factory: (context: GameContext) => DefinedGameModule): DefinedGame;
43
+ export type GameHandle = {
44
+ readonly mode: RuntimeMode;
45
+ readonly canvas: RuntimeCanvas;
46
+ readonly screen: Screen;
47
+ readonly clock: Clock;
48
+ readonly keyboard: KeyboardState;
49
+ readonly loaders: AssetLoaders;
50
+ readonly storage: Storage;
51
+ readonly diagnostics: readonly RuntimeDiagnostic[];
52
+ readonly module: GameModule;
53
+ readonly state: GameHandleState;
54
+ readonly failure: RuntimeFailure | null;
55
+ /**
56
+ * Resolves once the "preload gate" is satisfied: storage has been
57
+ * loaded and every asset requested while the game module was
58
+ * evaluated (Actor constructions, `images.x` touches, etc.) has
59
+ * settled. The runtime itself already holds frames until this is
60
+ * true; this is exposed for tests and host integrations that want to
61
+ * await readiness explicitly instead of polling `step()`.
62
+ */
63
+ readonly ready: Promise<void>;
64
+ readonly done: Promise<void>;
65
+ pause(): void;
66
+ resume(): void;
67
+ step(dt: number): void;
68
+ stop(): void;
69
+ dispose(): Promise<void>;
70
+ restart(source?: GameModule | string | DefinedGame): Promise<GameHandle>;
71
+ /** @deprecated Prefer restart(), which awaits cleanup before starting again. */
72
+ reload(source?: GameModule | string | DefinedGame): GameHandle;
73
+ };
74
+ /**
75
+ * The source bindings of a live zero-boilerplate game, or null. Hosts use
76
+ * `getGameInspector` from `js-game-zero/host`, which reads paths and
77
+ * serialises values on top of this.
78
+ */
79
+ export declare function getSourceInspector(handle: GameHandle): SourceInspector | null;
80
+ export declare function run(moduleOrSource: GameModule | string | DefinedGame, options?: RunOptions): GameHandle;
81
+ export declare function exit(): void;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * A small lexical scan of zero-boilerplate game source, used by the typo
3
+ * diagnostics to find the names a script actually *defines* at top level
4
+ * (as opposed to every identifier it merely mentions). It is deliberately
5
+ * not a parser: it tokenizes comments, strings, template literals (with
6
+ * nested substitutions), regex literals, identifiers and punctuators while
7
+ * tracking brace depth, and pattern-matches definitions on the token stream.
8
+ *
9
+ * On anything it cannot make sense of (an unterminated string, comment,
10
+ * template or regex, or unbalanced braces/parens) the scan reports itself
11
+ * incomplete and callers emit nothing: no diagnostic beats a wrong one.
12
+ */
13
+ export type SourceTokenType = "identifier" | "punctuator" | "literal";
14
+ export type SourceToken = {
15
+ readonly type: SourceTokenType;
16
+ readonly value: string;
17
+ /** Brace depth at the token: 0 means outside every `{…}` and `${…}`. */
18
+ readonly depth: number;
19
+ /** Parenthesis depth at the token: 0 means outside every `(…)`. */
20
+ readonly parens: number;
21
+ /** Square-bracket depth at the token: 0 means outside every `[…]`. */
22
+ readonly brackets: number;
23
+ };
24
+ export type SourceScan = {
25
+ /** False when the tokenizer gave up; the name lists are then empty. */
26
+ readonly complete: boolean;
27
+ /**
28
+ * Names given a function value at depth 0: `function NAME(`, and
29
+ * `NAME = function…`, `NAME = async …`, `NAME = (…) =>`, `NAME = x =>`
30
+ * (with or without `const`/`let`/`var`).
31
+ */
32
+ readonly topLevelFunctions: readonly string[];
33
+ /** Depth-0 assignment and declaration targets (`NAME = …`, `let NAME`). */
34
+ readonly topLevelAssignments: readonly string[];
35
+ };
36
+ /**
37
+ * Splits `source` into tokens, or returns null when it cannot be tokenized
38
+ * confidently. Comments vanish; strings, templates, regexes and numbers
39
+ * become `literal` tokens (the code inside template substitutions is
40
+ * tokenized normally, one brace deeper than the template).
41
+ */
42
+ export declare function tokenizeSource(source: string,
43
+ /** Return the tokens of source that leaves a bracket open at the end,
44
+ * rather than null, to find out what's open. */
45
+ { allowUnclosed }?: {
46
+ readonly allowUnclosed?: boolean;
47
+ }): SourceToken[] | null;
48
+ /** Finds the names `source` defines at top level; see {@link SourceScan}. */
49
+ export declare function scanSource(source: string): SourceScan;
@@ -0,0 +1,3 @@
1
+ export declare function normalizeStoragePath(path: string): string;
2
+ export declare function normalizeSandboxStoragePath(path: string): string;
3
+ export declare function sandboxStoragePath(projectRoot: string, safePath: string): string;