@jolly-pixel/runtime 1.0.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.
package/README.md ADDED
@@ -0,0 +1,167 @@
1
+ <p align="center"><h1 align="center">
2
+ runtime
3
+ </h1>
4
+
5
+ <p align="center">
6
+ JollyPixel Three.js runtime
7
+ </p>
8
+
9
+ ## 💡 Features
10
+
11
+ - Web runtime with [Vite](https://vite.dev/)
12
+ - Desktop runtime with [Electron.js](https://www.electronjs.org/)
13
+
14
+ ## 💃 Getting Started
15
+
16
+ This package is available in the Node Package Repository and can be easily installed with [npm](https://docs.npmjs.com/getting-started/what-is-npm) or [yarn](https://yarnpkg.com).
17
+
18
+ ```bash
19
+ $ npm i @jolly-pixel/runtime
20
+ # or
21
+ $ yarn add @jolly-pixel/runtime
22
+ ```
23
+
24
+ ## 👀 Usage example
25
+
26
+ The runtime needs a `<canvas>` element to render into. Start by creating an HTML file with a canvas and a module script entry point:
27
+
28
+ ```html
29
+ <!DOCTYPE html>
30
+ <html lang="en">
31
+
32
+ <head>
33
+ <meta charset="UTF-8">
34
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
35
+ <title>Game</title>
36
+ <link rel="stylesheet" href="./main.css">
37
+ </head>
38
+
39
+ <canvas tabindex="-1"></canvas>
40
+
41
+ <script type="module" src="./src/main.ts"></script>
42
+
43
+ </html>
44
+ ```
45
+
46
+ > [!TIP]
47
+ > The `tabindex="-1"` attribute on the canvas allows it to receive keyboard focus, which is required for capturing input events.
48
+
49
+ Then in your main script, create a `Player` instance and call `loadPlayer` to bootstrap everything (GPU detection, asset loading screen, game loop startup):
50
+
51
+ ```ts
52
+ import { Player, loadPlayer } from "@jolly-pixel/runtime";
53
+
54
+ const canvas = document.querySelector("canvas")!;
55
+
56
+ const player = new Player(canvas, {
57
+ // Displays a stats.js FPS panel — useful during development
58
+ includePerformanceStats: true
59
+ });
60
+
61
+ // The gameInstance gives you access to the engine systems
62
+ // (scene, renderer, input, etc.)
63
+ const { gameInstance } = player;
64
+
65
+ // loadPlayer will detect the GPU, show a loading screen,
66
+ // load all registered assets, then start the game loop.
67
+ loadPlayer(player)
68
+ .catch(console.error);
69
+ ```
70
+
71
+ ### Electron.js support
72
+
73
+ The runtime also works inside an [Electron](https://www.electronjs.org/) application.
74
+ Build your project with Vite first, then load the generated `dist/index.html` from the main process.
75
+
76
+ Create an `electron/main.js` file to set up the `BrowserWindow`:
77
+
78
+ ```js
79
+ import { fileURLToPath } from "node:url";
80
+ import path from "node:path";
81
+
82
+ import { app, BrowserWindow } from "electron";
83
+
84
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
85
+
86
+ function createWindow() {
87
+ const win = new BrowserWindow({
88
+ width: 800,
89
+ height: 600,
90
+ webPreferences: {
91
+ nodeIntegration: false,
92
+ contextIsolation: true,
93
+ enableRemoteModule: false,
94
+ preload: path.join(__dirname, "preload.js")
95
+ }
96
+ });
97
+
98
+ win.loadFile(
99
+ path.join(__dirname, "../dist/index.html")
100
+ );
101
+ }
102
+
103
+ app.whenReady().then(createWindow);
104
+
105
+ app.on("window-all-closed", () => {
106
+ if (process.platform !== "darwin") {
107
+ app.quit();
108
+ }
109
+ });
110
+ ```
111
+
112
+ Then add a `preload.js` alongside it to safely expose IPC channels
113
+ to the renderer:
114
+
115
+ ```js
116
+ const { contextBridge, ipcRenderer } = require("electron");
117
+
118
+ contextBridge.exposeInMainWorld("electron", {
119
+ send: (channel, data) => ipcRenderer.send(channel, data),
120
+ on: (channel, func) => ipcRenderer.on(
121
+ channel, (_, ...args) => func(...args)
122
+ )
123
+ });
124
+ ```
125
+
126
+ Finally, set the `main` field in your `package.json` to point to the Electron entry and add the relevant scripts:
127
+
128
+ ```json
129
+ {
130
+ "main": "electron/main.js",
131
+ "scripts": {
132
+ "start": "npm run build && electron .",
133
+ "build": "vite build"
134
+ }
135
+ }
136
+ ```
137
+
138
+ > [!NOTE]
139
+ > The Vite web runtime and the Electron desktop runtime share the exact same HTML file and application code. Only the shell that loads `dist/index.html` differs.
140
+
141
+ ## 📚 API
142
+
143
+ - [Player](./docs/Player.md)
144
+
145
+ ### `loadPlayer(player: Player, options?: LoadPlayerOptions)`
146
+
147
+ Bootstraps the runtime by detecting GPU capabilities, displaying a loading screen, loading all registered assets, and starting the game loop.
148
+
149
+ Returns a `Promise<void>` that resolves when loading completes, or shows an error on the loading screen if something fails.
150
+
151
+ ```ts
152
+ export interface LoadPlayerOptions {
153
+ /**
154
+ * @default 850
155
+ * Minimum delay (ms) before starting asset loading. Gives the loading UI time to render.
156
+ */
157
+ loadingDelay?: number;
158
+ }
159
+ ```
160
+
161
+ ### Custom loader component
162
+
163
+ In future releases, the loading component will be customizable.
164
+
165
+ ## License
166
+
167
+ MIT
@@ -0,0 +1,26 @@
1
+ import Stats from "stats.js";
2
+ import * as THREE from "three";
3
+ import { Systems } from "@jolly-pixel/engine";
4
+ export interface PlayerOptions {
5
+ /**
6
+ * @default false
7
+ * Whether to include performance statistics (eg: FPS, memory usage).
8
+ */
9
+ includePerformanceStats?: boolean;
10
+ }
11
+ export declare class Player {
12
+ #private;
13
+ gameInstance: Systems.GameInstance;
14
+ canvas: HTMLCanvasElement;
15
+ stats?: Stats;
16
+ clock: THREE.Clock;
17
+ manager: THREE.LoadingManager;
18
+ framesPerSecond: number;
19
+ constructor(canvas: HTMLCanvasElement, options?: PlayerOptions);
20
+ get running(): boolean;
21
+ start(): void;
22
+ stop(): void;
23
+ setFps(framesPerSecond: number | undefined): void;
24
+ tick: () => void;
25
+ }
26
+ //# sourceMappingURL=Player.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Player.d.ts","sourceRoot":"","sources":["../src/Player.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,UAAU,CAAC;AAC7B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EACL,OAAO,EACR,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,qBAAa,MAAM;;IACjB,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC;IACnC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,cAAqB;IAC1B,OAAO,uBAA8B;IAErC,eAAe,SAAM;gBAMnB,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE,aAAkB;IAyB7B,IAAI,OAAO,YAEV;IAED,KAAK;IAiBL,IAAI;IAaJ,MAAM,CACJ,eAAe,EAAE,MAAM,GAAG,SAAS,GAClC,IAAI;IAYP,IAAI,aAkBF;CACH"}
package/dist/Player.js ADDED
@@ -0,0 +1,81 @@
1
+ // Import Third-party Dependencies
2
+ import Stats from "stats.js";
3
+ import * as THREE from "three";
4
+ import { Systems } from "@jolly-pixel/engine";
5
+ export class Player {
6
+ gameInstance;
7
+ canvas;
8
+ stats;
9
+ clock = new THREE.Clock();
10
+ manager = new THREE.LoadingManager();
11
+ framesPerSecond = 60;
12
+ #isRunning = false;
13
+ #deltaTime = 0;
14
+ constructor(canvas, options = {}) {
15
+ if (!canvas) {
16
+ throw new Error("Canvas element is required to create a Runtime instance.");
17
+ }
18
+ this.canvas = canvas;
19
+ const scene = new Systems.SceneEngine();
20
+ const renderer = new Systems.ThreeRenderer(canvas, { scene, renderMode: "direct" });
21
+ this.gameInstance = new Systems.GameInstance(renderer, {
22
+ enableOnExit: true,
23
+ scene
24
+ });
25
+ this.gameInstance.setLoadingManager(this.manager);
26
+ if (options.includePerformanceStats) {
27
+ this.stats = new Stats();
28
+ this.stats.showPanel(0);
29
+ this.stats.dom.removeAttribute("style");
30
+ this.stats.dom.classList.add("stats");
31
+ }
32
+ }
33
+ get running() {
34
+ return this.#isRunning;
35
+ }
36
+ start() {
37
+ if (this.#isRunning) {
38
+ return;
39
+ }
40
+ this.#isRunning = true;
41
+ this.canvas.focus();
42
+ if (this.stats) {
43
+ document.body.appendChild(this.stats.dom);
44
+ }
45
+ this.gameInstance.connect();
46
+ const renderer = this.gameInstance.renderer.getSource();
47
+ renderer.setAnimationLoop(this.tick);
48
+ }
49
+ stop() {
50
+ if (!this.#isRunning) {
51
+ return;
52
+ }
53
+ this.#isRunning = false;
54
+ this.gameInstance.input.exited = true;
55
+ const renderer = this.gameInstance.renderer.getSource();
56
+ renderer.setAnimationLoop(null);
57
+ this.gameInstance.disconnect();
58
+ }
59
+ setFps(framesPerSecond) {
60
+ if (!framesPerSecond) {
61
+ return;
62
+ }
63
+ this.framesPerSecond = THREE.MathUtils.clamp(framesPerSecond, 1, 60);
64
+ }
65
+ tick = () => {
66
+ this.#deltaTime += this.clock.getDelta();
67
+ const interval = 1 / this.framesPerSecond;
68
+ if (this.#deltaTime >= interval) {
69
+ this.stats?.begin();
70
+ const exit = this.gameInstance.update(this.#deltaTime);
71
+ if (exit) {
72
+ this.stop();
73
+ return;
74
+ }
75
+ this.gameInstance.render();
76
+ this.#deltaTime %= interval;
77
+ this.stats?.end();
78
+ }
79
+ };
80
+ }
81
+ //# sourceMappingURL=Player.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Player.js","sourceRoot":"","sources":["../src/Player.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { Systems } from "@jolly-pixel/engine";
2
+ import { LitElement } from "lit";
3
+ export declare class Loading extends LitElement {
4
+ #private;
5
+ started: boolean;
6
+ completed: boolean;
7
+ progress: number;
8
+ maxProgress: number;
9
+ assetName: string;
10
+ errorMessage: string;
11
+ errorStack: string;
12
+ imageError: boolean;
13
+ static styles: import("lit").CSSResult;
14
+ constructor();
15
+ updated(changedProperties: Map<string, unknown>): void;
16
+ start(): Promise<void>;
17
+ complete(callback?: () => void): Promise<void>;
18
+ error(error: Error): void;
19
+ setAsset(asset: Systems.Asset): void;
20
+ setProgress(value: number, max: number): void;
21
+ getProgressPercentage(): number;
22
+ render(): import("lit-html").TemplateResult<1>;
23
+ }
24
+ //# sourceMappingURL=Loading.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Loading.d.ts","sourceRoot":"","sources":["../../src/components/Loading.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAY5C,qBAAa,OAAQ,SAAQ,UAAU;;IAK7B,OAAO,EAAE,OAAO,CAAC;IAGjB,SAAS,EAAE,OAAO,CAAC;IAGnB,QAAQ,EAAE,MAAM,CAAC;IAGjB,WAAW,EAAE,MAAM,CAAC;IAGpB,SAAS,EAAE,MAAM,CAAC;IAGlB,YAAY,EAAE,MAAM,CAAC;IAGrB,UAAU,EAAE,MAAM,CAAC;IAGnB,UAAU,EAAE,OAAO,CAAC;IAE5B,MAAM,CAAC,MAAM,0BAuSX;;IAcF,OAAO,CACL,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GACtC,IAAI;IA0BD,KAAK;IAQL,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpD,KAAK,CACH,KAAK,EAAE,KAAK;IAUd,QAAQ,CACN,KAAK,EAAE,OAAO,CAAC,KAAK;IAKtB,WAAW,CACT,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM;IAMb,qBAAqB,IAAI,MAAM;IAY/B,MAAM;CA+BP"}
@@ -0,0 +1,449 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ // Import Third-party Dependencies
11
+ import { Systems } from "@jolly-pixel/engine";
12
+ import { LitElement, css, html } from "lit";
13
+ import { classMap } from "lit/directives/class-map.js";
14
+ import { property, state } from "lit/decorators.js";
15
+ // Import Internal Dependencies
16
+ import * as timers from "../utils/timers.js";
17
+ // CONSTANTS
18
+ const kProgressAnimationDurationMs = 400;
19
+ const kFadeOutDurationMs = 500;
20
+ const kVelocityThreshold = 0.1;
21
+ export class Loading extends LitElement {
22
+ #lastProgressUpdate = 0;
23
+ #progressVelocity = 0;
24
+ static styles = css `
25
+ :host {
26
+ display: block;
27
+ transition: opacity 0.5s ease-out;
28
+ }
29
+
30
+ :host([completed]) {
31
+ opacity: 0;
32
+ }
33
+
34
+ #loading {
35
+ position: absolute;
36
+ top: 0;
37
+ bottom: 0;
38
+ left: 0;
39
+ right: 0;
40
+ color: #444;
41
+ font-size: 24px;
42
+ font-family: sans-serif;
43
+ display: flex;
44
+ flex-flow: column;
45
+ align-items: center;
46
+ justify-content: center;
47
+ background: #eee;
48
+ }
49
+
50
+ :host(:not([started])) #loading {
51
+ opacity: 0;
52
+ }
53
+
54
+ #loading a {
55
+ transition: opacity 0.3s ease-out;
56
+ position: relative;
57
+ text-decoration: none;
58
+ color: inherit;
59
+ display: flex;
60
+ flex-direction: column;
61
+ }
62
+
63
+ #loading a > * {
64
+ pointer-events: none;
65
+ }
66
+
67
+ #loading img {
68
+ width: 480px;
69
+ height: 280px;
70
+ max-width: 100%;
71
+ opacity: 0;
72
+ transform: translateY(-20px) scale(0.95);
73
+ animation: logo-fade-in 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
74
+ animation-delay: 0.2s;
75
+ }
76
+
77
+ #loading img.hidden {
78
+ display: none;
79
+ }
80
+
81
+ @keyframes logo-fade-in {
82
+ 0% {
83
+ opacity: 0;
84
+ transform: translateY(-20px) scale(0.95);
85
+ }
86
+ 100% {
87
+ opacity: 1;
88
+ transform: translateY(0) scale(1);
89
+ }
90
+ }
91
+
92
+ :host([completed]) #loading img {
93
+ animation: logo-fade-out 0.4s ease-out forwards;
94
+ }
95
+
96
+ @keyframes logo-fade-out {
97
+ 0% {
98
+ opacity: 1;
99
+ transform: translateY(0) scale(1);
100
+ }
101
+ 100% {
102
+ opacity: 0;
103
+ transform: translateY(-10px) scale(0.98);
104
+ }
105
+ }
106
+
107
+ #loading .asset {
108
+ margin-top: 20px;
109
+ text-align: center;
110
+ font-size: 13px;
111
+ font-weight: 500;
112
+ text-transform: uppercase;
113
+ letter-spacing: 2px;
114
+ color: #282e38ff;
115
+ opacity: 0;
116
+ animation: fade-slide-in 0.6s ease-out forwards;
117
+ animation-delay: 0.5s;
118
+ padding: 0 2em;
119
+ max-width: 100%;
120
+ overflow: hidden;
121
+ text-overflow: ellipsis;
122
+ white-space: nowrap;
123
+
124
+ /* Transition douce lors du changement d'asset */
125
+ transition: opacity 0.2s ease-out;
126
+ }
127
+
128
+ /* Effet subtil de "pulse" pendant le chargement */
129
+ @keyframes fade-slide-in {
130
+ 0% {
131
+ opacity: 0;
132
+ transform: translateY(10px);
133
+ }
134
+ 100% {
135
+ opacity: 0.8;
136
+ transform: translateY(0);
137
+ }
138
+ }
139
+
140
+ #loading .progress-container {
141
+ width: 100%;
142
+ height: 6px;
143
+ background: linear-gradient(
144
+ 180deg,
145
+ #b8bfb0 0%,
146
+ #d0d4c3 50%,
147
+ #b8bfb0 100%
148
+ );
149
+ overflow: hidden;
150
+ position: relative;
151
+ border-radius: 3px;
152
+ box-shadow:
153
+ inset 0 1px 2px rgba(0, 0, 0, 0.1),
154
+ 0 1px 0 rgba(255, 255, 255, 0.5);
155
+ opacity: 0;
156
+ animation: fade-slide-in 0.6s ease-out forwards;
157
+ animation-delay: 0.7s;
158
+ transform: translateZ(0);
159
+ backface-visibility: hidden;
160
+ }
161
+
162
+ #loading .progress-bar {
163
+ position: absolute;
164
+ top: 0;
165
+ left: 0;
166
+ width: 100%;
167
+ height: 100%;
168
+ background: linear-gradient(
169
+ 90deg,
170
+ #2a5d8f 0%,
171
+ #3E7CB8 50%,
172
+ #4a8fd8 100%
173
+ );
174
+ transform: scaleX(var(--progress, 0));
175
+ transform-origin: left center;
176
+ transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
177
+ will-change: transform;
178
+ box-shadow:
179
+ 0 0 10px rgba(62, 124, 184, 0.5),
180
+ 0 0 20px rgba(62, 124, 184, 0.3),
181
+ inset 0 1px 0 rgba(255, 255, 255, 0.3);
182
+ animation: progress-pulse 1.5s ease-in-out infinite;
183
+ backface-visibility: hidden;
184
+ }
185
+
186
+ #loading .progress-bar.speed-blur {
187
+ animation: speed-blur 0.3s ease;
188
+ }
189
+
190
+ #loading .progress-bar::before {
191
+ content: "";
192
+ position: absolute;
193
+ top: 0;
194
+ left: 0;
195
+ width: 100%;
196
+ height: 100%;
197
+ background: linear-gradient(
198
+ 90deg,
199
+ transparent 0%,
200
+ rgba(255, 255, 255, 0.15) 30%,
201
+ rgba(255, 255, 255, 0.4) 50%,
202
+ rgba(255, 255, 255, 0.15) 70%,
203
+ transparent 100%
204
+ );
205
+ animation: shimmer 2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
206
+ }
207
+
208
+ #loading .progress-bar::after {
209
+ content: "";
210
+ position: absolute;
211
+ top: 0;
212
+ left: 0;
213
+ width: 100%;
214
+ height: 100%;
215
+ background: linear-gradient(
216
+ 180deg,
217
+ rgba(255, 255, 255, 0.2) 0%,
218
+ transparent 50%,
219
+ rgba(0, 0, 0, 0.1) 100%
220
+ );
221
+ }
222
+
223
+ :host([completed]) .progress-bar {
224
+ animation: none;
225
+ box-shadow:
226
+ 0 0 10px rgba(62, 124, 184, 0.5),
227
+ 0 0 20px rgba(62, 124, 184, 0.3),
228
+ inset 0 1px 0 rgba(255, 255, 255, 0.3);
229
+ }
230
+
231
+ :host([completed]) .progress-bar::before {
232
+ animation: none;
233
+ }
234
+
235
+ @keyframes shimmer {
236
+ 0% {
237
+ transform: translateX(-100%);
238
+ }
239
+ 100% {
240
+ transform: translateX(100%);
241
+ }
242
+ }
243
+
244
+ @keyframes progress-pulse {
245
+ 0%, 100% {
246
+ box-shadow:
247
+ 0 0 10px rgba(62, 124, 184, 0.5),
248
+ 0 0 20px rgba(62, 124, 184, 0.3),
249
+ inset 0 1px 0 rgba(255, 255, 255, 0.3);
250
+ }
251
+ 50% {
252
+ box-shadow:
253
+ 0 0 15px rgba(62, 124, 184, 0.7),
254
+ 0 0 30px rgba(62, 124, 184, 0.5),
255
+ inset 0 1px 0 rgba(255, 255, 255, 0.4);
256
+ }
257
+ }
258
+
259
+ #loading div.error {
260
+ text-align: center;
261
+ padding: 0 2em;
262
+ font-size: 18px;
263
+ font-weight: bold;
264
+ letter-spacing: 0.5px;
265
+ font-family: Monaco, "DejaVu Sans Mono", "Lucida Console", "Andale Mono", monospace;
266
+ color: #BF360C;
267
+ text-transform: uppercase;
268
+ }
269
+
270
+ #loading pre.error {
271
+ text-align: left;
272
+ overflow: auto;
273
+ padding: 1em;
274
+ margin-top: 1em;
275
+ background: #CFD8DC;
276
+ color: #182024ff;
277
+ font-size: 15px;
278
+ border-radius: 4px;
279
+ }
280
+
281
+ /* Media queries pour mobile */
282
+ @media (max-width: 600px) {
283
+ #loading {
284
+ padding: 15px;
285
+ }
286
+
287
+ #loading .asset {
288
+ font-size: 11px;
289
+ letter-spacing: 1px;
290
+ margin-top: 15px;
291
+ }
292
+
293
+ #loading div.error {
294
+ font-size: 16px;
295
+ padding: 0 1em;
296
+ }
297
+
298
+ #loading pre.error {
299
+ font-size: 13px;
300
+ padding: 0.8em;
301
+ }
302
+ }
303
+
304
+ @media (max-width: 400px) {
305
+ #loading {
306
+ padding: 10px;
307
+ }
308
+
309
+ #loading .asset {
310
+ font-size: 10px;
311
+ letter-spacing: 0.5px;
312
+ margin-top: 12px;
313
+ }
314
+
315
+ #loading .progress-container {
316
+ height: 5px;
317
+ }
318
+ }
319
+ `;
320
+ constructor() {
321
+ super();
322
+ this.started = false;
323
+ this.completed = false;
324
+ this.progress = 0;
325
+ this.maxProgress = 100;
326
+ this.errorMessage = "";
327
+ this.errorStack = "";
328
+ this.assetName = "Loading runtime...";
329
+ this.imageError = false;
330
+ }
331
+ updated(changedProperties) {
332
+ if (changedProperties.has("progress") ||
333
+ changedProperties.has("maxProgress")) {
334
+ const percentage = this.getProgressPercentage() / 100;
335
+ this.style.setProperty("--progress", String(percentage));
336
+ this.#updateProgressVelocity(changedProperties);
337
+ }
338
+ }
339
+ #updateProgressVelocity(changedProperties) {
340
+ const now = performance.now();
341
+ const deltaTime = now - this.#lastProgressUpdate;
342
+ const previousProgress = changedProperties.get("progress") || 0;
343
+ this.#progressVelocity = (this.progress - previousProgress) / deltaTime;
344
+ this.#lastProgressUpdate = now;
345
+ }
346
+ async start() {
347
+ await this.updateComplete;
348
+ requestAnimationFrame(() => {
349
+ this.started = true;
350
+ });
351
+ }
352
+ async complete(callback) {
353
+ this.progress = this.maxProgress;
354
+ await this.updateComplete;
355
+ // progression animation end (400ms)
356
+ await timers.setTimeout(kProgressAnimationDurationMs);
357
+ this.completed = true;
358
+ // fade-out (500ms)
359
+ await timers.setTimeout(kFadeOutDurationMs);
360
+ this.remove();
361
+ callback?.();
362
+ }
363
+ error(error) {
364
+ this.errorMessage = error.message || "An error occurred";
365
+ const causeStackTrace = error?.cause?.stack ?? "";
366
+ this.errorStack = causeStackTrace === "" ? (error.stack || "") : causeStackTrace;
367
+ this.started = true;
368
+ this.completed = false;
369
+ }
370
+ setAsset(asset) {
371
+ this.assetName = asset.toString();
372
+ }
373
+ setProgress(value, max) {
374
+ this.progress = Math.max(0, Math.min(value, max));
375
+ this.maxProgress = max;
376
+ }
377
+ getProgressPercentage() {
378
+ if (this.maxProgress === 0) {
379
+ return 0;
380
+ }
381
+ return (this.progress / this.maxProgress) * 100;
382
+ }
383
+ #handleImageError() {
384
+ this.imageError = true;
385
+ }
386
+ render() {
387
+ const progressBarClasses = classMap({
388
+ "progress-bar": true,
389
+ "speed-blur": this.#progressVelocity > kVelocityThreshold
390
+ });
391
+ const imageClasses = classMap({
392
+ hidden: this.imageError
393
+ });
394
+ return html `
395
+ <div id="loading">
396
+ ${this.errorMessage ? html `
397
+ <div class="error">${this.errorMessage}</div>
398
+ <pre class="error">${this.errorStack}</pre>
399
+ ` : html `
400
+ <a href="https://github.com/JollyPixel" target="_blank">
401
+ <img
402
+ class="${imageClasses}"
403
+ src="./images/jollypixel-full-logo-min.svg"
404
+ @error="${this.#handleImageError}"
405
+ >
406
+ <p class="asset">${this.assetName}</p>
407
+ <div class="progress-container">
408
+ <div class="${progressBarClasses}"></div>
409
+ </div>
410
+ </a>
411
+ `}
412
+ </div>
413
+ `;
414
+ }
415
+ }
416
+ __decorate([
417
+ property({ type: Boolean, reflect: true }),
418
+ __metadata("design:type", Boolean)
419
+ ], Loading.prototype, "started", void 0);
420
+ __decorate([
421
+ property({ type: Boolean, reflect: true }),
422
+ __metadata("design:type", Boolean)
423
+ ], Loading.prototype, "completed", void 0);
424
+ __decorate([
425
+ state(),
426
+ __metadata("design:type", Number)
427
+ ], Loading.prototype, "progress", void 0);
428
+ __decorate([
429
+ state(),
430
+ __metadata("design:type", Number)
431
+ ], Loading.prototype, "maxProgress", void 0);
432
+ __decorate([
433
+ state(),
434
+ __metadata("design:type", String)
435
+ ], Loading.prototype, "assetName", void 0);
436
+ __decorate([
437
+ state(),
438
+ __metadata("design:type", String)
439
+ ], Loading.prototype, "errorMessage", void 0);
440
+ __decorate([
441
+ state(),
442
+ __metadata("design:type", String)
443
+ ], Loading.prototype, "errorStack", void 0);
444
+ __decorate([
445
+ state(),
446
+ __metadata("design:type", Boolean)
447
+ ], Loading.prototype, "imageError", void 0);
448
+ customElements.define("jolly-loading", Loading);
449
+ //# sourceMappingURL=Loading.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Loading.js","sourceRoot":"","sources":["../../src/components/Loading.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Player, type PlayerOptions } from "./Player.ts";
2
+ export interface LoadPlayerOptions {
3
+ loadingDelay?: number;
4
+ }
5
+ export declare function loadPlayer(player: Player, options?: LoadPlayerOptions): Promise<void>;
6
+ export { Player, type PlayerOptions };
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,iBAAsB,iBAoFhC;AAED,OAAO,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,71 @@
1
+ // Import Third-party Dependencies
2
+ import { Systems } from "@jolly-pixel/engine";
3
+ import { getGPUTier } from "detect-gpu";
4
+ // Import Internal Dependencies
5
+ import { Loading } from "./components/Loading.js";
6
+ import * as timers from "./utils/timers.js";
7
+ import { getDevicePixelRatio } from "./utils/getDevicePixelRatio.js";
8
+ import { Player } from "./Player.js";
9
+ export async function loadPlayer(player, options = {}) {
10
+ const { loadingDelay = 850 } = options;
11
+ const gpuTierPromise = getGPUTier();
12
+ player.canvas.style.opacity = "0";
13
+ player.canvas.style.transition = "opacity 0.5s ease-in";
14
+ let loadingElement = document.querySelector("jolly-loading");
15
+ if (loadingElement === null) {
16
+ loadingElement = document.createElement("jolly-loading");
17
+ document.body.appendChild(loadingElement);
18
+ }
19
+ const loadingComponent = loadingElement;
20
+ loadingComponent.start();
21
+ let loadingComplete = false;
22
+ const loadingCompletePromise = new Promise((resolve) => {
23
+ player.manager.onProgress = (_, loaded, total) => {
24
+ loadingComponent.setProgress(loaded, total);
25
+ if (loaded >= total && !loadingComplete) {
26
+ loadingComplete = true;
27
+ // Attendre un petit délai pour s'assurer que le DOM est mis à jour
28
+ setTimeout(() => void resolve(undefined), 100);
29
+ }
30
+ };
31
+ });
32
+ // Prevent keypress events from leaking out to a parent window
33
+ // They might trigger scrolling for instance
34
+ player.canvas.addEventListener("keypress", (event) => {
35
+ event.preventDefault();
36
+ });
37
+ // Make sure the focus is always on the game canvas wherever we click on the game window
38
+ document.addEventListener("click", () => player.canvas.focus());
39
+ try {
40
+ if (loadingDelay > 0) {
41
+ await timers.setTimeout(loadingDelay);
42
+ }
43
+ const { fps, isMobile = false, tier } = await gpuTierPromise;
44
+ player.setFps(fps);
45
+ player.gameInstance.renderer.getSource().setPixelRatio(getDevicePixelRatio(isMobile));
46
+ if (tier < 1) {
47
+ throw new Error("GPU is not powerful enough to run this game");
48
+ }
49
+ const context = { manager: player.manager };
50
+ setTimeout(() => {
51
+ Systems.Assets.autoload = true;
52
+ Systems.Assets.scheduleAutoload(context);
53
+ });
54
+ const waitingAssetsCount = Systems.Assets.waiting.size;
55
+ if (waitingAssetsCount > 0) {
56
+ await Systems.Assets.loadAssets(context, {
57
+ onStart: loadingComponent.setAsset.bind(loadingComponent)
58
+ });
59
+ await loadingCompletePromise;
60
+ }
61
+ await loadingComponent.complete(() => {
62
+ player.canvas.style.opacity = "1";
63
+ player.start();
64
+ });
65
+ }
66
+ catch (error) {
67
+ loadingComponent.error(error);
68
+ }
69
+ }
70
+ export { Player };
71
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function getDevicePixelRatio(isMobile: boolean): number;
2
+ //# sourceMappingURL=getDevicePixelRatio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDevicePixelRatio.d.ts","sourceRoot":"","sources":["../../src/utils/getDevicePixelRatio.ts"],"names":[],"mappings":"AAIA,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,OAAO,GAChB,MAAM,CAIR"}
@@ -0,0 +1,9 @@
1
+ // CONSTANTS
2
+ const kDesktopMaxPixelRatio = 1;
3
+ const kMobileMaxPixelRatio = 1.5;
4
+ export function getDevicePixelRatio(isMobile) {
5
+ return isMobile ?
6
+ Math.min(kMobileMaxPixelRatio, window.devicePixelRatio) :
7
+ Math.min(kDesktopMaxPixelRatio, window.devicePixelRatio);
8
+ }
9
+ //# sourceMappingURL=getDevicePixelRatio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDevicePixelRatio.js","sourceRoot":"","sources":["../../src/utils/getDevicePixelRatio.ts"],"names":[],"mappings":"AAAA,YAAY;AACZ,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAChC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,MAAM,UAAU,mBAAmB,CACjC,QAAiB;IAEjB,OAAO,QAAQ,CAAC,CAAC;QACf,IAAI,CAAC,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function setTimeout(timeout: number): Promise<void>;
2
+ //# sourceMappingURL=timers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../../src/utils/timers.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -0,0 +1,6 @@
1
+ export function setTimeout(timeout) {
2
+ return new Promise((resolve) => {
3
+ window.setTimeout(() => resolve(), timeout);
4
+ });
5
+ }
6
+ //# sourceMappingURL=timers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timers.js","sourceRoot":"","sources":["../../src/utils/timers.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,UAAU,CACxB,OAAe;IAEf,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@jolly-pixel/runtime",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "prepublish": "rimraf ./dist && tsc -b",
9
+ "build": "tsc",
10
+ "test-only": "node --test test/**/*.spec.ts",
11
+ "test": "c8 -r html npm run test-only"
12
+ },
13
+ "publishConfig": {
14
+ "registry": "https://registry.npmjs.org",
15
+ "access": "public",
16
+ "provenance": false
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/JollyPixel/editor.git",
21
+ "directory": "packages/runtime"
22
+ },
23
+ "keywords": [],
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "directories": {
28
+ "doc": "docs",
29
+ "test": "test"
30
+ },
31
+ "author": "GENTILHOMME Thomas <gentilhomme.thomas@gmail.com>",
32
+ "license": "MIT",
33
+ "dependencies": {
34
+ "@jolly-pixel/engine": "^1.0.0",
35
+ "detect-gpu": "^5.0.70",
36
+ "lit": "^3.3.1",
37
+ "stats.js": "^0.17.0",
38
+ "three": "^0.182.0"
39
+ }
40
+ }