Skip to content

Commit ca274cf

Browse files
authored
refactor(runtime)!: rename Player to Runtime and introduce GameInstance context (#152)
1 parent 64a510e commit ca274cf

File tree

11 files changed

+107
-65
lines changed

11 files changed

+107
-65
lines changed

.changeset/thirty-ravens-crash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@jolly-pixel/runtime": major
3+
---
4+
5+
Rename Player to Runtime and introduce GameInstance context

packages/editors/model/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ import {
44
Camera3DControls,
55
ModelRenderer
66
} from "@jolly-pixel/engine";
7-
import { Player, loadPlayer } from "@jolly-pixel/runtime";
7+
import { Runtime, loadRuntime } from "@jolly-pixel/runtime";
88
import * as THREE from "three";
99

1010
// Import Internal Dependencies
1111
import { PlayerBehavior } from "./PlayerBehavior.ts";
1212

1313
const runtime = initRuntime();
14-
loadPlayer(runtime)
14+
loadRuntime(runtime)
1515
.catch(console.error);
1616

1717
function initRuntime() {
1818
const canvasHTMLElement = document.querySelector("canvas") as HTMLCanvasElement;
19-
const runtime = new Player(canvasHTMLElement, {
19+
const runtime = new Runtime(canvasHTMLElement, {
2020
includePerformanceStats: true
2121
});
2222
const { gameInstance } = runtime;

packages/editors/voxel-map/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
Actor,
44
Camera3DControls
55
} from "@jolly-pixel/engine";
6-
import { Player, loadPlayer } from "@jolly-pixel/runtime";
6+
import { Runtime, loadRuntime } from "@jolly-pixel/runtime";
77
import { TreeView } from "@jolly-pixel/fs-tree/tree-view";
88

99
// Import Internal Dependencies
@@ -14,12 +14,12 @@ const runtime = initRuntime();
1414
initTreeView();
1515
initCubeSelector();
1616

17-
loadPlayer(runtime)
17+
loadRuntime(runtime)
1818
.catch(console.error);
1919

2020
function initRuntime() {
2121
const canvasHTMLElement = document.querySelector("#game-container > canvas") as HTMLCanvasElement;
22-
const runtime = new Player(canvasHTMLElement, {
22+
const runtime = new Runtime(canvasHTMLElement, {
2323
includePerformanceStats: true
2424
});
2525
const { gameInstance } = runtime;

packages/editors/voxel-map/src/shapeEditor.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
import {
33
Actor
44
} from "@jolly-pixel/engine";
5-
import { Player, loadPlayer } from "@jolly-pixel/runtime";
5+
import { Runtime, loadRuntime } from "@jolly-pixel/runtime";
66
import * as THREE from "three";
77

88
// Import Internal Dependencies
99
import { OrbitCameraControls } from "./components/OrbitCamera.ts";
1010

1111
const canvasHTMLElement = document.querySelector("canvas") as HTMLCanvasElement;
12-
const runtime = new Player(canvasHTMLElement, {
12+
const runtime = new Runtime(canvasHTMLElement, {
1313
includePerformanceStats: true
1414
});
1515
const { gameInstance } = runtime;
@@ -30,7 +30,7 @@ const mesh = new THREE.Mesh(
3030
scene.add(new THREE.AmbientLight(new THREE.Color("#ffffff"), 3));
3131
scene.add(mesh);
3232

33-
loadPlayer(runtime)
33+
loadRuntime(runtime)
3434
.catch(console.error);
3535

3636
function createGeometry(size: number): THREE.BufferGeometry {

packages/experimental/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
TextRenderer,
99
createViewHelper
1010
} from "@jolly-pixel/engine";
11-
import { Player, loadPlayer } from "@jolly-pixel/runtime";
11+
import { Runtime, loadRuntime } from "@jolly-pixel/runtime";
1212
import * as THREE from "three";
1313
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
1414
import { OutputPass } from "three/addons/postprocessing/OutputPass.js";
@@ -17,7 +17,7 @@ import { OutputPass } from "three/addons/postprocessing/OutputPass.js";
1717
// import { SpriteRenderer } from "./components/sprite/SpriteRenderer.class.ts";
1818

1919
const canvasHTMLElement = document.querySelector("canvas") as HTMLCanvasElement;
20-
const runtime = new Player(canvasHTMLElement, {
20+
const runtime = new Runtime(canvasHTMLElement, {
2121
includePerformanceStats: true
2222
});
2323
const { gameInstance } = runtime;
@@ -113,5 +113,5 @@ canvasHTMLElement.addEventListener("click", async() => {
113113
await ab.play("boss.tech-space");
114114
});
115115

116-
loadPlayer(runtime)
116+
loadRuntime(runtime)
117117
.catch(console.error);

packages/experimental/src/indexUI.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import {
44
UIRenderer,
55
UISprite
66
} from "@jolly-pixel/engine";
7-
import { Player, loadPlayer } from "@jolly-pixel/runtime";
7+
import { Runtime, loadRuntime } from "@jolly-pixel/runtime";
88

99
const canvasHTMLElement = document.querySelector("canvas") as HTMLCanvasElement;
10-
const runtime = new Player(canvasHTMLElement, {
10+
const runtime = new Runtime(canvasHTMLElement, {
1111
includePerformanceStats: true
1212
});
1313
const { gameInstance } = runtime;
@@ -46,5 +46,5 @@ uiButton.onClick.connect(() => {
4646
console.log("Button clicked!");
4747
});
4848

49-
loadPlayer(runtime)
49+
loadRuntime(runtime)
5050
.catch(console.error);

packages/runtime/ARCHITECTURE.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ and how its components interact during the lifecycle of a game session.
77

88
```
99
src/
10-
├── index.ts Entry point — exports Player and loadPlayer
11-
├── Player.ts Core runtime class (game loop, renderer, clock)
10+
├── index.ts Entry point — exports Runtime and loadRuntime
11+
├── Runtime.ts Core runtime class (game loop, renderer, clock)
1212
├── components/
1313
│ └── Loading.ts <jolly-loading> Lit web component
1414
└── utils/
@@ -34,15 +34,15 @@ and the **engine** (`@jolly-pixel/engine`). It is responsible for:
3434
│ provides <canvas>
3535
3636
┌─────────────────────────────────────────────────┐
37-
loadPlayer()
37+
loadRuntime()
3838
│ ┌───────────┐ ┌────────────┐ ┌────────────┐ │
3939
│ │ detect- │ │ <jolly- │ │ Assets │ │
4040
│ │ gpu │ │ loading> │ │ loader │ │
4141
│ └─────┬─────┘ └─────┬──────┘ └──────┬─────┘ │
4242
│ │ │ │ │
4343
│ ▼ ▼ ▼ │
4444
│ ┌──────────────────────────────────────────┐ │
45-
│ │ Player │ │
45+
│ │ Runtime │ │
4646
│ │ ┌────────────────────────────────────┐ │ │
4747
│ │ │ GameInstance │ │ │
4848
│ │ │ (SceneEngine + ThreeRenderer) │ │ │
@@ -54,11 +54,11 @@ and the **engine** (`@jolly-pixel/engine`). It is responsible for:
5454

5555
## Bootstrap sequence
5656

57-
`loadPlayer()` orchestrates the full startup. Below is the ordered
57+
`loadRuntime()` orchestrates the full startup. Below is the ordered
5858
sequence of operations:
5959

6060
```
61-
loadPlayer(player)
61+
loadRuntime(runtime)
6262
6363
├─ 1. Start GPU detection ─────────────── getGPUTier() (async, runs in parallel)
6464
@@ -82,7 +82,7 @@ loadPlayer(player)
8282
│ ├─ fade-out ────────────────────── 500 ms
8383
│ └─ remove <jolly-loading>
8484
85-
└─ 8. Start player ───────────────────── player.start()
85+
└─ 8. Start runtime ──────────────────── runtime.start()
8686
├─ canvas opacity: 1 fade-in with CSS transition
8787
├─ gameInstance.connect()
8888
└─ setAnimationLoop(tick) game loop begins
@@ -93,7 +93,7 @@ loadPlayer(player)
9393
9494
## Game loop
9595

96-
The `Player.tick` callback is called by Three.js via `setAnimationLoop`.
96+
The `Runtime.tick` callback is called by Three.js via `setAnimationLoop`.
9797
It implements a **fixed-timestep** pattern capped at the target FPS:
9898

9999
```
@@ -109,15 +109,15 @@ setAnimationLoop(tick)
109109
└─ if deltaTime >= interval
110110
├─ stats.begin()
111111
├─ gameInstance.update(deltaTime)
112-
│ └─ returns true → player.stop()
112+
│ └─ returns true → runtime.stop()
113113
├─ gameInstance.render()
114114
├─ deltaTime %= interval
115115
└─ stats.end()
116116
```
117117

118118
The loop stops when:
119119
- `gameInstance.update()` signals an exit
120-
- `player.stop()` is called manually
120+
- `runtime.stop()` is called manually
121121

122122
## Loading screen
123123

packages/runtime/README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,25 +46,25 @@ The runtime needs a `<canvas>` element to render into. Start by creating an HTML
4646
> [!TIP]
4747
> The `tabindex="-1"` attribute on the canvas allows it to receive keyboard focus, which is required for capturing input events.
4848
49-
Then in your main script, create a `Player` instance and call `loadPlayer` to bootstrap everything (GPU detection, asset loading screen, game loop startup):
49+
Then in your main script, create a `Runtime` instance and call `loadRuntime` to bootstrap everything (GPU detection, asset loading screen, game loop startup):
5050

5151
```ts
52-
import { Player, loadPlayer } from "@jolly-pixel/runtime";
52+
import { Runtime, loadRuntime } from "@jolly-pixel/runtime";
5353

5454
const canvas = document.querySelector("canvas")!;
5555

56-
const player = new Player(canvas, {
56+
const runtime = new Runtime(canvas, {
5757
// Displays a stats.js FPS panel — useful during development
5858
includePerformanceStats: true
5959
});
6060

6161
// The gameInstance gives you access to the engine systems
6262
// (scene, renderer, input, etc.)
63-
const { gameInstance } = player;
63+
const { gameInstance } = runtime;
6464

65-
// loadPlayer will detect the GPU, show a loading screen,
65+
// loadRuntime will detect the GPU, show a loading screen,
6666
// load all registered assets, then start the game loop.
67-
loadPlayer(player)
67+
loadRuntime(runtime)
6868
.catch(console.error);
6969
```
7070

@@ -140,16 +140,16 @@ Finally, set the `main` field in your `package.json` to point to the Electron en
140140
141141
## 📚 API
142142
143-
- [Player](./docs/Player.md)
143+
- [Runtime](./docs/Runtime.md)
144144
145-
### `loadPlayer(player: Player, options?: LoadPlayerOptions)`
145+
### `loadRuntime(runtime: Runtime, options?: LoadRuntimeOptions)`
146146
147147
Bootstraps the runtime by detecting GPU capabilities, displaying a loading screen, loading all registered assets, and starting the game loop.
148148
149149
Returns a `Promise<void>` that resolves when loading completes, or shows an error on the loading screen if something fails.
150150
151151
```ts
152-
export interface LoadPlayerOptions {
152+
export interface LoadRuntimeOptions {
153153
/**
154154
* @default 850
155155
* Minimum delay (ms) before starting asset loading. Gives the loading UI time to render.
Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Player
1+
# Runtime
22

33
Main runtime class. Wraps a Three.js renderer, a game instance, and the
44
update/render loop. Manages the full lifecycle: construction, starting,
@@ -9,16 +9,20 @@ stopping, and frame-rate control.
99
- **setFps(fps)**: Clamps the target FPS between `1` and `60`. No-op if `fps` is falsy.
1010

1111
```ts
12-
interface PlayerOptions {
12+
interface RuntimeOptions<TContext = Record<string, unknown>> {
1313
/**
1414
* When true, a stats.js panel is appended to the document to show FPS.
1515
* @default false
1616
*/
1717
includePerformanceStats?: boolean;
18+
/**
19+
* Optional context object passed to the GameInstance.
20+
*/
21+
context?: TContext;
1822
}
1923

20-
class Player {
21-
gameInstance: Systems.GameInstance;
24+
class Runtime<TContext = Record<string, unknown>> {
25+
gameInstance: Systems.GameInstance<THREE.WebGLRenderer, TContext>;
2226
canvas: HTMLCanvasElement;
2327
stats?: Stats;
2428
clock: THREE.Clock;
@@ -27,7 +31,7 @@ class Player {
2731

2832
get running(): boolean;
2933

30-
constructor(canvas: HTMLCanvasElement, options?: PlayerOptions);
34+
constructor(canvas: HTMLCanvasElement, options?: RuntimeOptions<TContext>);
3135

3236
start(): void;
3337
stop(): void;
@@ -41,16 +45,35 @@ class Player {
4145
## Usage
4246

4347
```ts
44-
import { Player, loadPlayer } from "@jolly-pixel/runtime";
48+
import { Runtime, loadRuntime } from "@jolly-pixel/runtime";
4549

4650
const canvas = document.querySelector("canvas")!;
47-
const player = new Player(canvas, {
51+
const runtime = new Runtime(canvas, {
4852
includePerformanceStats: true
4953
});
5054

51-
const { gameInstance } = player;
55+
const { gameInstance } = runtime;
5256
// Work with the gameInstance
5357

54-
loadPlayer(player)
58+
loadRuntime(runtime)
5559
.catch(console.error);
5660
```
61+
62+
## Type-safe context
63+
64+
The `TContext` generic lets you pass a typed context object to the
65+
underlying `GameInstance`:
66+
67+
```ts
68+
interface MyContext {
69+
score: number;
70+
level: string;
71+
}
72+
73+
const runtime = new Runtime<MyContext>(canvas, {
74+
context: { score: 0, level: "intro" }
75+
});
76+
77+
// runtime.gameInstance.context is typed as MyContext
78+
runtime.gameInstance.context.score; // number
79+
```
Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,30 @@ import Stats from "stats.js";
33
import * as THREE from "three";
44

55
// Import Internal Dependencies
6-
import { Systems } from "@jolly-pixel/engine";
6+
import {
7+
Systems,
8+
type GlobalAudio
9+
} from "@jolly-pixel/engine";
710

8-
export interface PlayerOptions {
11+
export interface RuntimeOptions<TContext = Record<string, unknown>> {
912
/**
1013
* @default false
1114
* Whether to include performance statistics (eg: FPS, memory usage).
1215
*/
1316
includePerformanceStats?: boolean;
17+
/**
18+
* Optional context object passed to the GameInstance.
19+
*/
20+
context?: TContext;
21+
/**
22+
* Optional global audio object passed to the GameInstance.
23+
* If not provided, a default audio context will be created.
24+
*/
25+
audio?: GlobalAudio;
1426
}
1527

16-
export class Player {
17-
gameInstance: Systems.GameInstance;
28+
export class Runtime<TContext = Record<string, unknown>> {
29+
gameInstance: Systems.GameInstance<THREE.WebGLRenderer, TContext>;
1830
loop = new Systems.FixedTimeStep();
1931

2032
canvas: HTMLCanvasElement;
@@ -25,7 +37,7 @@ export class Player {
2537

2638
constructor(
2739
canvas: HTMLCanvasElement,
28-
options: PlayerOptions = {}
40+
options: RuntimeOptions<TContext> = Object.create(null)
2941
) {
3042
if (!canvas) {
3143
throw new Error("Canvas element is required to create a Runtime instance.");
@@ -38,7 +50,9 @@ export class Player {
3850
) as unknown as Systems.Renderer<THREE.WebGLRenderer>;
3951
this.gameInstance = new Systems.GameInstance(renderer, {
4052
enableOnExit: true,
41-
scene
53+
scene,
54+
context: options.context,
55+
audio: options.audio
4256
});
4357
this.gameInstance.setLoadingManager(this.manager);
4458

0 commit comments

Comments
 (0)