@starweb-libs/engine 0.0.2 → 0.0.3
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/LICENSE +21 -21
- package/README.md +28 -28
- package/dist/{assets.d.ts → assets.d.mts} +6 -3
- package/dist/assets.mjs +39 -0
- package/dist/assets.mjs.map +1 -0
- package/dist/canvas.d.mts +36 -0
- package/dist/canvas.mjs +50 -0
- package/dist/canvas.mjs.map +1 -0
- package/dist/input/{keyboard.d.ts → keyboard.d.mts} +9 -6
- package/dist/input/keyboard.mjs +61 -0
- package/dist/input/keyboard.mjs.map +1 -0
- package/dist/input/{pointer.d.ts → pointer.d.mts} +12 -9
- package/dist/input/pointer.mjs +105 -0
- package/dist/input/pointer.mjs.map +1 -0
- package/dist/update.d.mts +37 -0
- package/dist/update.mjs +82 -0
- package/dist/update.mjs.map +1 -0
- package/dist/validate.d.mts +16 -0
- package/dist/validate.mjs +55 -0
- package/dist/validate.mjs.map +1 -0
- package/package.json +56 -47
- package/dist/assets.d.ts.map +0 -1
- package/dist/assets.js +0 -36
- package/dist/assets.js.map +0 -1
- package/dist/canvas.d.ts +0 -31
- package/dist/canvas.d.ts.map +0 -1
- package/dist/canvas.js +0 -45
- package/dist/canvas.js.map +0 -1
- package/dist/input/keyboard.d.ts.map +0 -1
- package/dist/input/keyboard.js +0 -48
- package/dist/input/keyboard.js.map +0 -1
- package/dist/input/pointer.d.ts.map +0 -1
- package/dist/input/pointer.js +0 -91
- package/dist/input/pointer.js.map +0 -1
- package/dist/update.d.ts +0 -34
- package/dist/update.d.ts.map +0 -1
- package/dist/update.js +0 -77
- package/dist/update.js.map +0 -1
- package/dist/validate.d.ts +0 -13
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js +0 -61
- package/dist/validate.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.mjs","names":[],"sources":["../src/update.ts"],"sourcesContent":["import { clearFramePointer } from \"./input/pointer.js\";\nimport { clearFrameKeyboard } from \"./input/keyboard.js\";\n\n/** Options for configuring the game loop. */\nexport interface LoopOptions {\n /** Fixed timestep in **ms**, or \"variable\" for frame-rate dependent updates. */\n tickRate: number | \"variable\";\n /** Maximum elapsed time per frame in **ms**. */\n maxDelta: number;\n /** Automatically pause the loop when the page is hidden. */\n pauseOnHidden: boolean;\n}\n\n/** Handle returned by {@link startLoop} to control the running game loop. */\nexport interface LoopHandle {\n /** Permanently stops the loop and cancels the animation frame. */\n stop(): void;\n /** Pauses update and render calls without cancelling the animation frame. */\n pause(): void;\n /** Resumes a paused loop. */\n resume(): void;\n}\n\n/** Starts a game loop using `requestAnimationFrame`.\n *\n * When `tickRate` is a number, uses a fixed timestep accumulator\n * so `update` is always called with a consistent delta.\n * When `\"variable\"`, `update` receives the raw frame delta.\n *\n * @param update - Called each tick with the delta time in **ms**.\n * @param render - Called once per frame after all update ticks.\n * @param options - Loop configuration. See {@link LoopOptions}.\n * @returns A {@link LoopHandle} to stop, pause, or resume the loop.\n *\n * @throws {RangeError} If `tickRate` is not `\"variable\"` or a positive finite number.\n * @throws {RangeError} If `maxDelta` is not a positive finite number.\n */\nexport function startLoop(\n update: (/** **Milliseconds** */ dt: number) => void,\n render: () => void,\n options: LoopOptions,\n): LoopHandle {\n const { tickRate, maxDelta, pauseOnHidden } = options;\n if (typeof tickRate === \"number\" && (!Number.isFinite(tickRate) || tickRate <= 0)) {\n throw new RangeError(\n `startLoop: tickRate must be \"variable\" or a positive finite number, got ${tickRate}`\n )\n }\n if (!Number.isFinite(maxDelta) || maxDelta <= 0) {\n throw new RangeError(\n `startLoop: maxDelta must be a positive finite number, got ${maxDelta}`\n )\n }\n\n let reqId: number | null = null;\n let accumulator = 0;\n let lastTime = performance.now();\n let paused = false;\n\n let visibilityCleanup: (() => void) | null = null;\n if (pauseOnHidden) {\n const onVisibility = () => { paused = document.hidden; };\n document.addEventListener(\"visibilitychange\", onVisibility);\n visibilityCleanup = () => document.removeEventListener(\"visibilitychange\", onVisibility);\n }\n\n function frame(nowMs: number) {\n if (paused) {\n lastTime = nowMs;\n reqId = requestAnimationFrame(frame);\n return;\n }\n\n const elapsed = Math.min(nowMs - lastTime, maxDelta);\n lastTime = nowMs;\n\n if (tickRate === \"variable\") {\n clearFrameKeyboard();\n clearFramePointer();\n update(elapsed);\n } else {\n accumulator += elapsed;\n let ticked = false;\n while (accumulator >= tickRate) {\n if (!ticked) {\n clearFrameKeyboard();\n clearFramePointer();\n ticked = true;\n }\n update(tickRate);\n accumulator -= tickRate;\n }\n }\n\n render();\n reqId = requestAnimationFrame(frame);\n }\n reqId = requestAnimationFrame(frame);\n\n return {\n stop: () => {\n if (reqId !== null) { cancelAnimationFrame(reqId); reqId = null; }\n visibilityCleanup?.();\n },\n pause: () => { paused = true; },\n resume: () => { paused = false; },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAqCA,SAAgB,UACd,QACA,QACA,SACY;CACZ,MAAM,EAAE,UAAU,UAAU,kBAAkB;CAC9C,IAAI,OAAO,aAAa,aAAa,CAAC,OAAO,SAAS,QAAQ,KAAK,YAAY,IAC7E,MAAM,IAAI,WACR,2EAA2E,UAC7E;CAEF,IAAI,CAAC,OAAO,SAAS,QAAQ,KAAK,YAAY,GAC5C,MAAM,IAAI,WACR,6DAA6D,UAC/D;CAGF,IAAI,QAAuB;CAC3B,IAAI,cAAc;CAClB,IAAI,WAAc,YAAY,IAAI;CAClC,IAAI,SAAc;CAElB,IAAI,oBAAyC;CAC7C,IAAI,eAAe;EACjB,MAAM,qBAAqB;GAAE,SAAS,SAAS;EAAQ;EACvD,SAAS,iBAAiB,oBAAoB,YAAY;EAC1D,0BAA0B,SAAS,oBAAoB,oBAAoB,YAAY;CACzF;CAEA,SAAS,MAAM,OAAe;EAC5B,IAAI,QAAQ;GACV,WAAW;GACX,QAAQ,sBAAsB,KAAK;GACnC;EACF;EAEA,MAAM,UAAU,KAAK,IAAI,QAAQ,UAAU,QAAQ;EACnD,WAAW;EAEX,IAAI,aAAa,YAAY;GAC3B,mBAAmB;GACnB,kBAAkB;GAClB,OAAO,OAAO;EAChB,OAAO;GACL,eAAe;GACf,IAAI,SAAS;GACb,OAAO,eAAe,UAAU;IAC9B,IAAI,CAAC,QAAQ;KACX,mBAAmB;KACnB,kBAAkB;KAClB,SAAS;IACX;IACA,OAAO,QAAQ;IACf,eAAe;GACjB;EACF;EAEA,OAAO;EACP,QAAQ,sBAAsB,KAAK;CACrC;CACA,QAAQ,sBAAsB,KAAK;CAEnC,OAAO;EACL,YAAc;GACZ,IAAI,UAAU,MAAM;IAAE,qBAAqB,KAAK;IAAG,QAAQ;GAAM;GACjE,oBAAoB;EACtB;EACA,aAAc;GAAE,SAAS;EAAM;EAC/B,cAAc;GAAE,SAAS;EAAO;CAClC;AACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/validate.d.ts
|
|
2
|
+
declare function isObj(x: unknown): x is Record<string, unknown>;
|
|
3
|
+
declare function optBool(obj: Record<string, unknown>, key: string, ctx: string): boolean | undefined;
|
|
4
|
+
declare function num(obj: Record<string, unknown>, key: string, ctx: string): number;
|
|
5
|
+
declare function optNum(obj: Record<string, unknown>, key: string, ctx: string): number | undefined;
|
|
6
|
+
declare function str(obj: Record<string, unknown>, key: string, ctx: string): string;
|
|
7
|
+
declare function optStr(obj: Record<string, unknown>, key: string, ctx: string): string | undefined;
|
|
8
|
+
declare function arr(obj: Record<string, unknown>, key: string, ctx: string): unknown[];
|
|
9
|
+
declare function makeCollector(): {
|
|
10
|
+
errors: string[];
|
|
11
|
+
tryGet: <T>(fn: () => T) => T | undefined;
|
|
12
|
+
};
|
|
13
|
+
type Collector = ReturnType<typeof makeCollector>;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { Collector, arr, isObj, makeCollector, num, optBool, optNum, optStr, str };
|
|
16
|
+
//# sourceMappingURL=validate.d.mts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//#region src/validate.ts
|
|
2
|
+
function isObj(x) {
|
|
3
|
+
return typeof x === "object" && x !== null;
|
|
4
|
+
}
|
|
5
|
+
function optBool(obj, key, ctx) {
|
|
6
|
+
const v = obj[key];
|
|
7
|
+
if (v === void 0) return void 0;
|
|
8
|
+
if (typeof v !== "boolean") throw new Error(`${ctx}: ${key} must be a boolean if present`);
|
|
9
|
+
return v;
|
|
10
|
+
}
|
|
11
|
+
function num(obj, key, ctx) {
|
|
12
|
+
const v = obj[key];
|
|
13
|
+
if (typeof v !== "number" || !Number.isFinite(v)) throw new Error(`${ctx}: ${key} must be a finite number`);
|
|
14
|
+
return v;
|
|
15
|
+
}
|
|
16
|
+
function optNum(obj, key, ctx) {
|
|
17
|
+
const v = obj[key];
|
|
18
|
+
if (v === void 0) return void 0;
|
|
19
|
+
if (typeof v !== "number" || !Number.isFinite(v)) throw new Error(`${ctx}: ${key} must be a finite number if present`);
|
|
20
|
+
return v;
|
|
21
|
+
}
|
|
22
|
+
function str(obj, key, ctx) {
|
|
23
|
+
const v = obj[key];
|
|
24
|
+
if (typeof v !== "string" || v.length === 0) throw new Error(`${ctx}: ${key} must be a non-empty string`);
|
|
25
|
+
return v;
|
|
26
|
+
}
|
|
27
|
+
function optStr(obj, key, ctx) {
|
|
28
|
+
const v = obj[key];
|
|
29
|
+
if (v === void 0) return void 0;
|
|
30
|
+
if (typeof v !== "string" || v.length === 0) throw new Error(`${ctx}: ${key} must be a non-empty string if present`);
|
|
31
|
+
return v;
|
|
32
|
+
}
|
|
33
|
+
function arr(obj, key, ctx) {
|
|
34
|
+
const v = obj[key];
|
|
35
|
+
if (!Array.isArray(v)) throw new Error(`${ctx}: ${key} must be an array`);
|
|
36
|
+
return v;
|
|
37
|
+
}
|
|
38
|
+
function makeCollector() {
|
|
39
|
+
const errors = [];
|
|
40
|
+
return {
|
|
41
|
+
errors,
|
|
42
|
+
tryGet: (fn) => {
|
|
43
|
+
try {
|
|
44
|
+
return fn();
|
|
45
|
+
} catch (e) {
|
|
46
|
+
errors.push(e.message);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { arr, isObj, makeCollector, num, optBool, optNum, optStr, str };
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=validate.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.mjs","names":[],"sources":["../src/validate.ts"],"sourcesContent":["export function isObj(x: unknown): x is Record<string, unknown> {\n return typeof x === \"object\" && x !== null;\n}\n\nexport function optBool(obj: Record<string, unknown>, key: string, ctx: string): boolean | undefined {\n const v = obj[key];\n if (v === undefined) return undefined;\n if (typeof v !== \"boolean\") throw new Error(`${ctx}: ${key} must be a boolean if present`);\n return v;\n}\n\nexport function num(obj: Record<string, unknown>, key: string, ctx: string): number {\n const v = obj[key];\n if (typeof v !== \"number\" || !Number.isFinite(v)) throw new Error(\n `${ctx}: ${key} must be a finite number`\n );\n return v;\n}\n\nexport function optNum(obj: Record<string, unknown>, key: string, ctx: string): number | undefined {\n const v = obj[key];\n if (v === undefined) return undefined;\n if (typeof v !== \"number\" || !Number.isFinite(v)) throw new Error(\n `${ctx}: ${key} must be a finite number if present`\n );\n return v;\n}\n\nexport function str(obj: Record<string, unknown>, key: string, ctx: string): string {\n const v = obj[key];\n if (typeof v !== \"string\" || v.length === 0) throw new Error(\n `${ctx}: ${key} must be a non-empty string`\n );\n return v;\n}\n\nexport function optStr(obj: Record<string, unknown>, key: string, ctx: string): string | undefined {\n const v = obj[key];\n if (v === undefined) return undefined;\n if (typeof v !== \"string\" || v.length === 0) throw new Error(\n `${ctx}: ${key} must be a non-empty string if present`\n );\n return v;\n}\n\nexport function arr(obj: Record<string, unknown>, key: string, ctx: string): unknown[] {\n const v = obj[key];\n if (!Array.isArray(v)) throw new Error(`${ctx}: ${key} must be an array`);\n return v;\n}\n\nexport function makeCollector() {\n const errors: string[] = [];\n return {\n errors,\n tryGet: <T>(fn: () => T): T | undefined => {\n try { return fn(); } catch (e) { errors.push((e as Error).message); return undefined; }\n },\n };\n}\n\nexport type Collector = ReturnType<typeof makeCollector>;\n"],"mappings":";AAAA,SAAgB,MAAM,GAA0C;CAC9D,OAAO,OAAO,MAAM,YAAY,MAAM;AACxC;AAEA,SAAgB,QAAQ,KAA8B,KAAa,KAAkC;CACnG,MAAM,IAAI,IAAI;CACd,IAAI,MAAM,KAAA,GAAW,OAAO,KAAA;CAC5B,IAAI,OAAO,MAAM,WAAW,MAAM,IAAI,MAAM,GAAG,IAAI,IAAI,IAAI,8BAA8B;CACzF,OAAO;AACT;AAEA,SAAgB,IAAI,KAA8B,KAAa,KAAqB;CAClF,MAAM,IAAI,IAAI;CACd,IAAI,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,GAAG,MAAM,IAAI,MAC1D,GAAG,IAAI,IAAI,IAAI,yBACjB;CACA,OAAO;AACT;AAEA,SAAgB,OAAO,KAA8B,KAAa,KAAiC;CACjG,MAAM,IAAI,IAAI;CACd,IAAI,MAAM,KAAA,GAAW,OAAO,KAAA;CAC5B,IAAI,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,GAAG,MAAM,IAAI,MAC1D,GAAG,IAAI,IAAI,IAAI,oCACjB;CACA,OAAO;AACT;AAEA,SAAgB,IAAI,KAA8B,KAAa,KAAqB;CAClF,MAAM,IAAI,IAAI;CACd,IAAI,OAAO,MAAM,YAAY,EAAE,WAAW,GAAG,MAAM,IAAI,MACrD,GAAG,IAAI,IAAI,IAAI,4BACjB;CACA,OAAO;AACT;AAEA,SAAgB,OAAO,KAA8B,KAAa,KAAiC;CACjG,MAAM,IAAI,IAAI;CACd,IAAI,MAAM,KAAA,GAAW,OAAO,KAAA;CAC5B,IAAI,OAAO,MAAM,YAAY,EAAE,WAAW,GAAG,MAAM,IAAI,MACrD,GAAG,IAAI,IAAI,IAAI,uCACjB;CACA,OAAO;AACT;AAEA,SAAgB,IAAI,KAA8B,KAAa,KAAwB;CACrF,MAAM,IAAI,IAAI;CACd,IAAI,CAAC,MAAM,QAAQ,CAAC,GAAG,MAAM,IAAI,MAAM,GAAG,IAAI,IAAI,IAAI,kBAAkB;CACxE,OAAO;AACT;AAEA,SAAgB,gBAAgB;CAC9B,MAAM,SAAmB,CAAC;CAC1B,OAAO;EACL;EACA,SAAY,OAA+B;GACzC,IAAI;IAAE,OAAO,GAAG;GAAG,SAAS,GAAG;IAAE,OAAO,KAAM,EAAY,OAAO;IAAG;GAAkB;EACxF;CACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,47 +1,56 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@starweb-libs/engine",
|
|
3
|
-
"description": "A lightweight 2D game engine for the browser",
|
|
4
|
-
"author": "Mason L'Etoile",
|
|
5
|
-
"version": "0.0.
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/starweb-libs/engine.git"
|
|
10
|
-
},
|
|
11
|
-
"homepage": "https://github.com/starweb-libs/engine#readme",
|
|
12
|
-
"bugs": { "url": "https://github.com/starweb-libs/engine/issues" },
|
|
13
|
-
"keywords": ["game-engine", "canvas", "2d", "typescript", "browser", "starweb"],
|
|
14
|
-
"type": "module",
|
|
15
|
-
"devDependencies": {
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"import": "./dist/
|
|
29
|
-
},
|
|
30
|
-
"./
|
|
31
|
-
"types": "./dist/
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@starweb-libs/engine",
|
|
3
|
+
"description": "A lightweight 2D game engine for the browser",
|
|
4
|
+
"author": "Mason L'Etoile",
|
|
5
|
+
"version": "0.0.3",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/starweb-libs/engine.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/starweb-libs/engine#readme",
|
|
12
|
+
"bugs": { "url": "https://github.com/starweb-libs/engine/issues" },
|
|
13
|
+
"keywords": ["game-engine", "canvas", "2d", "typescript", "browser", "starweb"],
|
|
14
|
+
"type": "module",
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "~6.0.2",
|
|
17
|
+
"tsdown": "^0.22.0"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsdown",
|
|
21
|
+
"prepare": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"files": ["dist"],
|
|
24
|
+
"exports": {
|
|
25
|
+
"./assets.js": {
|
|
26
|
+
"types": "./dist/assets.d.mts",
|
|
27
|
+
"@starweb-libs/source": "./src/assets.ts",
|
|
28
|
+
"import": "./dist/assets.mjs"
|
|
29
|
+
},
|
|
30
|
+
"./canvas.js": {
|
|
31
|
+
"types": "./dist/canvas.d.mts",
|
|
32
|
+
"@starweb-libs/source": "./src/canvas.ts",
|
|
33
|
+
"import": "./dist/canvas.mjs"
|
|
34
|
+
},
|
|
35
|
+
"./input/keyboard.js": {
|
|
36
|
+
"types": "./dist/input/keyboard.d.mts",
|
|
37
|
+
"@starweb-libs/source": "./src/input/keyboard.ts",
|
|
38
|
+
"import": "./dist/input/keyboard.mjs"
|
|
39
|
+
},
|
|
40
|
+
"./input/pointer.js": {
|
|
41
|
+
"types": "./dist/input/pointer.d.mts",
|
|
42
|
+
"@starweb-libs/source": "./src/input/pointer.ts",
|
|
43
|
+
"import": "./dist/input/pointer.mjs"
|
|
44
|
+
},
|
|
45
|
+
"./update.js": {
|
|
46
|
+
"types": "./dist/update.d.mts",
|
|
47
|
+
"@starweb-libs/source": "./src/update.ts",
|
|
48
|
+
"import": "./dist/update.mjs"
|
|
49
|
+
},
|
|
50
|
+
"./validate.js": {
|
|
51
|
+
"types": "./dist/validate.d.mts",
|
|
52
|
+
"@starweb-libs/source": "./src/validate.ts",
|
|
53
|
+
"import": "./dist/validate.mjs"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
package/dist/assets.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAOhE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,GACZ,iBAAiB,CAanB"}
|
package/dist/assets.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/** Loads an image from the given Path or URL.
|
|
2
|
-
*
|
|
3
|
-
* @param src - Path or URL of the image to load.
|
|
4
|
-
* @returns A promise that resolves with the loaded {@link HTMLImageElement}.
|
|
5
|
-
* @throws {Error} If the image fails to load.
|
|
6
|
-
*/
|
|
7
|
-
export function loadImage(src) {
|
|
8
|
-
return new Promise((resolve, reject) => {
|
|
9
|
-
const img = new Image();
|
|
10
|
-
img.onload = () => resolve(img);
|
|
11
|
-
img.onerror = () => reject(new Error(`Failed to load image: ${src}`));
|
|
12
|
-
img.src = src;
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
/** Returns a new offscreen canvas with the source image tinted by the given colour.
|
|
16
|
-
* Non-transparent pixels are filled with `color`; transparency is preserved.
|
|
17
|
-
*
|
|
18
|
-
* @param source - The source image to tint.
|
|
19
|
-
* @param color - Any valid CSS colour string.
|
|
20
|
-
* @returns An offscreen {@link HTMLCanvasElement} with the tinted result.
|
|
21
|
-
* @throws {Error} If a 2D context cannot be obtained.
|
|
22
|
-
*/
|
|
23
|
-
export function tintImage(source, color) {
|
|
24
|
-
const off = document.createElement("canvas");
|
|
25
|
-
off.width = source.width;
|
|
26
|
-
off.height = source.height;
|
|
27
|
-
const c = off.getContext("2d");
|
|
28
|
-
if (!c)
|
|
29
|
-
throw new Error("Failed to get offscreen 2d context");
|
|
30
|
-
c.drawImage(source, 0, 0);
|
|
31
|
-
c.globalCompositeOperation = "source-in";
|
|
32
|
-
c.fillStyle = color;
|
|
33
|
-
c.fillRect(0, 0, off.width, off.height);
|
|
34
|
-
return off;
|
|
35
|
-
}
|
|
36
|
-
//# sourceMappingURL=assets.js.map
|
package/dist/assets.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../src/assets.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,GAAG,CAAC,MAAM,GAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,GAAG,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,yBAAyB,GAAG,EAAE,CAAC,CAAC,CAAC;QACtE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CACvB,MAAwB,EACxB,KAAa;IAEb,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC7C,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IACzB,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3B,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IAE9D,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,wBAAwB,GAAG,WAAW,CAAC;IACzC,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAExC,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/canvas.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/** Options for configuring the game canvas. */
|
|
2
|
-
export interface CanvasOptions {
|
|
3
|
-
/** Enables or disables `imageSmoothingEnabled` on the canvas context. Default: `true`. */
|
|
4
|
-
imageSmoothing?: boolean;
|
|
5
|
-
}
|
|
6
|
-
/** The result of {@link createGameCanvas}. */
|
|
7
|
-
export interface GameCanvas {
|
|
8
|
-
/** The underlying canvas element. */
|
|
9
|
-
canvas: HTMLCanvasElement;
|
|
10
|
-
/** The 2D rendering context for the canvas. */
|
|
11
|
-
ctx: CanvasRenderingContext2D;
|
|
12
|
-
/** Canvas width and height. */
|
|
13
|
-
size: {
|
|
14
|
-
readonly width: number;
|
|
15
|
-
readonly height: number;
|
|
16
|
-
};
|
|
17
|
-
/** Removes the canvas from the DOM and cleans up the resize listener. */
|
|
18
|
-
destroy: () => void;
|
|
19
|
-
}
|
|
20
|
-
/** Creates a full-window canvas and appends it to `document.body`.
|
|
21
|
-
*
|
|
22
|
-
* The canvas is automatically resized to fill the window on creation,
|
|
23
|
-
* and on every subsequent `resize` event.
|
|
24
|
-
*
|
|
25
|
-
* @returns The canvas element, its 2D context, and a `destroy` function
|
|
26
|
-
* to remove the canvas and clean up the resize listener.
|
|
27
|
-
*
|
|
28
|
-
* @throws {Error} If a 2D canvas context cannot be obtained.
|
|
29
|
-
*/
|
|
30
|
-
export declare function createGameCanvas({ imageSmoothing }?: CanvasOptions): GameCanvas;
|
|
31
|
-
//# sourceMappingURL=canvas.d.ts.map
|
package/dist/canvas.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../src/canvas.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B,0FAA0F;IAC1F,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,8CAA8C;AAC9C,MAAM,WAAW,UAAU;IACzB,qCAAqC;IACrC,MAAM,EAAG,iBAAiB,CAAC;IAC3B,+CAA+C;IAC/C,GAAG,EAAM,wBAAwB,CAAC;IAClC,+BAA+B;IAC/B,IAAI,EAAK;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,yEAAyE;IACzE,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,cAAqB,EAAE,GAAE,aAAkB,GAC5C,UAAU,CAmCZ"}
|
package/dist/canvas.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/** Creates a full-window canvas and appends it to `document.body`.
|
|
2
|
-
*
|
|
3
|
-
* The canvas is automatically resized to fill the window on creation,
|
|
4
|
-
* and on every subsequent `resize` event.
|
|
5
|
-
*
|
|
6
|
-
* @returns The canvas element, its 2D context, and a `destroy` function
|
|
7
|
-
* to remove the canvas and clean up the resize listener.
|
|
8
|
-
*
|
|
9
|
-
* @throws {Error} If a 2D canvas context cannot be obtained.
|
|
10
|
-
*/
|
|
11
|
-
export function createGameCanvas({ imageSmoothing = true } = {}) {
|
|
12
|
-
const canvas = document.createElement("canvas");
|
|
13
|
-
document.body.appendChild(canvas);
|
|
14
|
-
const ctx = canvas.getContext("2d");
|
|
15
|
-
if (!ctx)
|
|
16
|
-
throw new Error("2D canvas context not found");
|
|
17
|
-
const size = { width: 0, height: 0 };
|
|
18
|
-
const onResize = () => {
|
|
19
|
-
const dpr = window.devicePixelRatio ?? 1;
|
|
20
|
-
size.width = window.innerWidth;
|
|
21
|
-
size.height = window.innerHeight;
|
|
22
|
-
canvas.width = size.width * dpr;
|
|
23
|
-
canvas.height = size.height * dpr;
|
|
24
|
-
canvas.style.width = `${size.width}px`;
|
|
25
|
-
canvas.style.height = `${size.height}px`;
|
|
26
|
-
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
27
|
-
ctx.imageSmoothingEnabled = imageSmoothing;
|
|
28
|
-
};
|
|
29
|
-
window.addEventListener("resize", onResize);
|
|
30
|
-
onResize();
|
|
31
|
-
let destroyed = false;
|
|
32
|
-
return {
|
|
33
|
-
canvas,
|
|
34
|
-
ctx,
|
|
35
|
-
size,
|
|
36
|
-
destroy: () => {
|
|
37
|
-
if (destroyed)
|
|
38
|
-
return;
|
|
39
|
-
destroyed = true;
|
|
40
|
-
window.removeEventListener("resize", onResize);
|
|
41
|
-
canvas.remove();
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
//# sourceMappingURL=canvas.js.map
|
package/dist/canvas.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"canvas.js","sourceRoot":"","sources":["../src/canvas.ts"],"names":[],"mappings":"AAkBA;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC9B,EAAE,cAAc,GAAG,IAAI,KAAoB,EAAE;IAE7C,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAElC,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAEzD,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAErC,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,MAAM,GAAG,GAAO,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,KAAK,GAAK,MAAM,CAAC,UAAU,CAAC;QACjC,IAAI,CAAC,MAAM,GAAI,MAAM,CAAC,WAAW,CAAC;QAClC,MAAM,CAAC,KAAK,GAAI,IAAI,CAAC,KAAK,GAAI,GAAG,CAAC;QAClC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAI,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC;QACzC,GAAG,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACvC,GAAG,CAAC,qBAAqB,GAAG,cAAc,CAAC;IAC7C,CAAC,CAAA;IACD,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5C,QAAQ,EAAE,CAAC;IAEX,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,OAAO;QACL,MAAM;QACN,GAAG;QACH,IAAI;QACJ,OAAO,EAAE,GAAG,EAAE;YACZ,IAAI,SAAS;gBAAE,OAAO;YACtB,SAAS,GAAG,IAAI,CAAC;YACjB,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../src/input/keyboard.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,IAAI,CAiBzC;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAA+B;AAE5E;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAwC;AAEzF,wFAAwF;AACxF,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC;AAED,sDAAsD;AACtD,wBAAgB,aAAa,IAAI,IAAI,CAAuB"}
|
package/dist/input/keyboard.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
let isKeyboardInitialized = false;
|
|
2
|
-
const keys = new Set();
|
|
3
|
-
const pressedThisFrame = new Set();
|
|
4
|
-
let pressedFrame = [];
|
|
5
|
-
const onKeyDown = (e) => {
|
|
6
|
-
if (!keys.has(e.code))
|
|
7
|
-
pressedThisFrame.add(e.code);
|
|
8
|
-
keys.add(e.code);
|
|
9
|
-
};
|
|
10
|
-
const onKeyUp = (e) => { keys.delete(e.code); };
|
|
11
|
-
const onBlur = () => { keys.clear(); pressedThisFrame.clear(); };
|
|
12
|
-
/** Initializes keyboard input listeners.
|
|
13
|
-
* @returns A cleanup function that removes all listeners and clears state.
|
|
14
|
-
* @throws {Error} If already initialized.
|
|
15
|
-
*/
|
|
16
|
-
export function initKeyboard() {
|
|
17
|
-
if (isKeyboardInitialized)
|
|
18
|
-
throw new Error("initKeyboard: already initialized, call cleanup first");
|
|
19
|
-
isKeyboardInitialized = true;
|
|
20
|
-
window.addEventListener("keydown", onKeyDown);
|
|
21
|
-
window.addEventListener("keyup", onKeyUp);
|
|
22
|
-
window.addEventListener("blur", onBlur);
|
|
23
|
-
return () => {
|
|
24
|
-
isKeyboardInitialized = false;
|
|
25
|
-
keys.clear();
|
|
26
|
-
pressedThisFrame.clear();
|
|
27
|
-
flushKeyboard();
|
|
28
|
-
window.removeEventListener("keydown", onKeyDown);
|
|
29
|
-
window.removeEventListener("keyup", onKeyUp);
|
|
30
|
-
window.removeEventListener("blur", onBlur);
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
/** Returns `true` if the key is currently held down.
|
|
34
|
-
* @param code - A `KeyboardEvent.code` value (e.g. `"KeyA"`, `"Space"`, `"Digit1"`).
|
|
35
|
-
*/
|
|
36
|
-
export function isDown(code) { return keys.has(code); }
|
|
37
|
-
/** Returns `true` if the key was pressed this frame.
|
|
38
|
-
* @param code - A `KeyboardEvent.code` value (e.g. `"KeyA"`, `"Space"`).
|
|
39
|
-
*/
|
|
40
|
-
export function wasPressed(code) { return pressedFrame.includes(code); }
|
|
41
|
-
/** Advances the per-frame pressed state. Called once per frame by {@link startLoop}. */
|
|
42
|
-
export function clearFrameKeyboard() {
|
|
43
|
-
pressedFrame = [...pressedThisFrame];
|
|
44
|
-
pressedThisFrame.clear();
|
|
45
|
-
}
|
|
46
|
-
/** Clears the per-frame pressed state immediately. */
|
|
47
|
-
export function flushKeyboard() { pressedFrame = []; }
|
|
48
|
-
//# sourceMappingURL=keyboard.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard.js","sourceRoot":"","sources":["../../src/input/keyboard.ts"],"names":[],"mappings":"AAAA,IAAI,qBAAqB,GAAG,KAAK,CAAC;AAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;AAC/B,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;AAC3C,IAAI,YAAY,GAAsB,EAAE,CAAC;AAEzC,MAAM,SAAS,GAAG,CAAC,CAAgB,EAAE,EAAE;IACrC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC;AACF,MAAM,OAAO,GAAG,CAAC,CAAgB,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,MAAM,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AAEjE;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,IAAI,qBAAqB;QAAE,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACpG,qBAAqB,GAAG,IAAI,CAAC;IAE7B,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC9C,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAExC,OAAO,GAAG,EAAE;QACV,qBAAqB,GAAG,KAAK,CAAC;QAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,gBAAgB,CAAC,KAAK,EAAE,CAAC;QACzB,aAAa,EAAE,CAAC;QAChB,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACjD,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC7C,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAA;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,IAAY,IAAiB,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAE5E;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,IAAa,OAAO,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEzF,wFAAwF;AACxF,MAAM,UAAU,kBAAkB;IAChC,YAAY,GAAG,CAAC,GAAG,gBAAgB,CAAC,CAAC;IACrC,gBAAgB,CAAC,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,aAAa,KAAW,YAAY,GAAG,EAAE,CAAC,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pointer.d.ts","sourceRoot":"","sources":["../../src/input/pointer.ts"],"names":[],"mappings":"AAyCA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAuBjE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,SAAI,GAAG,OAAO,CAAkC;AAEpF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,SAAI,GAAG,OAAO,CAA2C;AAEjG;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,SAAI,GAAG,OAAO,CAA2C;AAElG,4EAA4E;AAC5E,wBAAgB,QAAQ,IAAI,MAAM,CAAiB;AAEnD,4EAA4E;AAC5E,wBAAgB,QAAQ,IAAI,MAAM,CAAiB;AAEnD,kGAAkG;AAClG,wBAAgB,iBAAiB,IAAI,IAAI,CAKxC;AAED,gEAAgE;AAChE,wBAAgB,YAAY,IAAI,IAAI,CAA2C"}
|
package/dist/input/pointer.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
let isPointerInitialized = false;
|
|
2
|
-
const down = new Set();
|
|
3
|
-
const clicked = new Set();
|
|
4
|
-
const released = new Set();
|
|
5
|
-
let clickedFrame = [];
|
|
6
|
-
let releasedFrame = [];
|
|
7
|
-
let canvasRef = null;
|
|
8
|
-
let posX = 0;
|
|
9
|
-
let posY = 0;
|
|
10
|
-
function clearDown() {
|
|
11
|
-
down.clear();
|
|
12
|
-
clicked.clear();
|
|
13
|
-
released.clear();
|
|
14
|
-
}
|
|
15
|
-
const updatePos = (e) => {
|
|
16
|
-
if (!canvasRef)
|
|
17
|
-
return;
|
|
18
|
-
const rect = canvasRef.getBoundingClientRect();
|
|
19
|
-
posX = e.clientX - rect.left;
|
|
20
|
-
posY = e.clientY - rect.top;
|
|
21
|
-
};
|
|
22
|
-
const onDown = (e) => {
|
|
23
|
-
updatePos(e);
|
|
24
|
-
if (!down.has(e.button))
|
|
25
|
-
clicked.add(e.button);
|
|
26
|
-
down.add(e.button);
|
|
27
|
-
};
|
|
28
|
-
const onUp = (e) => {
|
|
29
|
-
updatePos(e);
|
|
30
|
-
down.delete(e.button);
|
|
31
|
-
released.add(e.button);
|
|
32
|
-
};
|
|
33
|
-
const onMove = (e) => updatePos(e);
|
|
34
|
-
const onBlur = () => clearDown();
|
|
35
|
-
const onMenu = (e) => {
|
|
36
|
-
clearDown();
|
|
37
|
-
e.preventDefault();
|
|
38
|
-
};
|
|
39
|
-
/** Initializes pointer input listeners and binds to the given canvas for coordinate mapping.
|
|
40
|
-
* @param canvas - The canvas element used to transform pointer coordinates.
|
|
41
|
-
* @returns A cleanup function that removes all listeners and clears state.
|
|
42
|
-
* @throws {Error} If already initialized.
|
|
43
|
-
*/
|
|
44
|
-
export function initPointer(canvas) {
|
|
45
|
-
if (isPointerInitialized)
|
|
46
|
-
throw new Error("initPointer: already initialized, call cleanup first");
|
|
47
|
-
isPointerInitialized = true;
|
|
48
|
-
canvasRef = canvas;
|
|
49
|
-
window.addEventListener("pointerdown", onDown);
|
|
50
|
-
window.addEventListener("pointerup", onUp);
|
|
51
|
-
window.addEventListener("pointermove", onMove);
|
|
52
|
-
window.addEventListener("blur", onBlur);
|
|
53
|
-
window.addEventListener("contextmenu", onMenu);
|
|
54
|
-
return () => {
|
|
55
|
-
isPointerInitialized = false;
|
|
56
|
-
canvasRef = null;
|
|
57
|
-
clearDown();
|
|
58
|
-
flushPointer();
|
|
59
|
-
window.removeEventListener("pointerdown", onDown);
|
|
60
|
-
window.removeEventListener("pointerup", onUp);
|
|
61
|
-
window.removeEventListener("pointermove", onMove);
|
|
62
|
-
window.removeEventListener("blur", onBlur);
|
|
63
|
-
window.removeEventListener("contextmenu", onMenu);
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
/** Returns `true` if the given pointer button is currently held down.
|
|
67
|
-
* @param button - Pointer button index. Default: `0` (primary).
|
|
68
|
-
*/
|
|
69
|
-
export function isPointerDown(button = 0) { return down.has(button); }
|
|
70
|
-
/** Returns `true` if the given button was clicked this frame.
|
|
71
|
-
* @param button - Pointer button index. Default: `0` (primary).
|
|
72
|
-
*/
|
|
73
|
-
export function wasPointerClicked(button = 0) { return clickedFrame.includes(button); }
|
|
74
|
-
/** Returns `true` if the given button was released this frame.
|
|
75
|
-
* @param button - Pointer button index. Default: `0` (primary).
|
|
76
|
-
*/
|
|
77
|
-
export function wasPointerReleased(button = 0) { return releasedFrame.includes(button); }
|
|
78
|
-
/** Returns the pointer's current X position in canvas pixel coordinates. */
|
|
79
|
-
export function pointerX() { return posX; }
|
|
80
|
-
/** Returns the pointer's current Y position in canvas pixel coordinates. */
|
|
81
|
-
export function pointerY() { return posY; }
|
|
82
|
-
/** Advances the per-frame click and release state. Called once per frame by {@link startLoop}. */
|
|
83
|
-
export function clearFramePointer() {
|
|
84
|
-
clickedFrame = [...clicked];
|
|
85
|
-
releasedFrame = [...released];
|
|
86
|
-
clicked.clear();
|
|
87
|
-
released.clear();
|
|
88
|
-
}
|
|
89
|
-
/** Clears the per-frame click and release state immediately. */
|
|
90
|
-
export function flushPointer() { clickedFrame = []; releasedFrame = []; }
|
|
91
|
-
//# sourceMappingURL=pointer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pointer.js","sourceRoot":"","sources":["../../src/input/pointer.ts"],"names":[],"mappings":"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"}
|
package/dist/update.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/** Options for configuring the game loop. */
|
|
2
|
-
export interface LoopOptions {
|
|
3
|
-
/** Fixed timestep in **ms**, or "variable" for frame-rate dependent updates. */
|
|
4
|
-
tickRate: number | "variable";
|
|
5
|
-
/** Maximum elapsed time per frame in **ms**. */
|
|
6
|
-
maxDelta: number;
|
|
7
|
-
/** Automatically pause the loop when the page is hidden. */
|
|
8
|
-
pauseOnHidden: boolean;
|
|
9
|
-
}
|
|
10
|
-
/** Handle returned by {@link startLoop} to control the running game loop. */
|
|
11
|
-
export interface LoopHandle {
|
|
12
|
-
/** Permanently stops the loop and cancels the animation frame. */
|
|
13
|
-
stop(): void;
|
|
14
|
-
/** Pauses update and render calls without cancelling the animation frame. */
|
|
15
|
-
pause(): void;
|
|
16
|
-
/** Resumes a paused loop. */
|
|
17
|
-
resume(): void;
|
|
18
|
-
}
|
|
19
|
-
/** Starts a game loop using `requestAnimationFrame`.
|
|
20
|
-
*
|
|
21
|
-
* When `tickRate` is a number, uses a fixed timestep accumulator
|
|
22
|
-
* so `update` is always called with a consistent delta.
|
|
23
|
-
* When `"variable"`, `update` receives the raw frame delta.
|
|
24
|
-
*
|
|
25
|
-
* @param update - Called each tick with the delta time in **ms**.
|
|
26
|
-
* @param render - Called once per frame after all update ticks.
|
|
27
|
-
* @param options - Loop configuration. See {@link LoopOptions}.
|
|
28
|
-
* @returns A {@link LoopHandle} to stop, pause, or resume the loop.
|
|
29
|
-
*
|
|
30
|
-
* @throws {RangeError} If `tickRate` is not `"variable"` or a positive finite number.
|
|
31
|
-
* @throws {RangeError} If `maxDelta` is not a positive finite number.
|
|
32
|
-
*/
|
|
33
|
-
export declare function startLoop(update: (/** **Milliseconds** */ dt: number) => void, render: () => void, options: LoopOptions): LoopHandle;
|
|
34
|
-
//# sourceMappingURL=update.d.ts.map
|
package/dist/update.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"AAGA,6CAA6C;AAC7C,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,QAAQ,EAAE,MAAM,GAAG,UAAU,CAAC;IAC9B,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,6EAA6E;AAC7E,MAAM,WAAW,UAAU;IACzB,kEAAkE;IAClE,IAAI,IAAM,IAAI,CAAC;IACf,6EAA6E;IAC7E,KAAK,IAAK,IAAI,CAAC;IACf,6BAA6B;IAC7B,MAAM,IAAI,IAAI,CAAC;CAChB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,CAAC,uBAAuB,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,EACpD,MAAM,EAAE,MAAM,IAAI,EAClB,OAAO,EAAE,WAAW,GACnB,UAAU,CAkEZ"}
|
package/dist/update.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { clearFramePointer } from "./input/pointer.js";
|
|
2
|
-
import { clearFrameKeyboard } from "./input/keyboard.js";
|
|
3
|
-
/** Starts a game loop using `requestAnimationFrame`.
|
|
4
|
-
*
|
|
5
|
-
* When `tickRate` is a number, uses a fixed timestep accumulator
|
|
6
|
-
* so `update` is always called with a consistent delta.
|
|
7
|
-
* When `"variable"`, `update` receives the raw frame delta.
|
|
8
|
-
*
|
|
9
|
-
* @param update - Called each tick with the delta time in **ms**.
|
|
10
|
-
* @param render - Called once per frame after all update ticks.
|
|
11
|
-
* @param options - Loop configuration. See {@link LoopOptions}.
|
|
12
|
-
* @returns A {@link LoopHandle} to stop, pause, or resume the loop.
|
|
13
|
-
*
|
|
14
|
-
* @throws {RangeError} If `tickRate` is not `"variable"` or a positive finite number.
|
|
15
|
-
* @throws {RangeError} If `maxDelta` is not a positive finite number.
|
|
16
|
-
*/
|
|
17
|
-
export function startLoop(update, render, options) {
|
|
18
|
-
const { tickRate, maxDelta, pauseOnHidden } = options;
|
|
19
|
-
if (typeof tickRate === "number" && (!Number.isFinite(tickRate) || tickRate <= 0)) {
|
|
20
|
-
throw new RangeError(`startLoop: tickRate must be "variable" or a positive finite number, got ${tickRate}`);
|
|
21
|
-
}
|
|
22
|
-
if (!Number.isFinite(maxDelta) || maxDelta <= 0) {
|
|
23
|
-
throw new RangeError(`startLoop: maxDelta must be a positive finite number, got ${maxDelta}`);
|
|
24
|
-
}
|
|
25
|
-
let reqId = null;
|
|
26
|
-
let accumulator = 0;
|
|
27
|
-
let lastTime = performance.now();
|
|
28
|
-
let paused = false;
|
|
29
|
-
let visibilityCleanup = null;
|
|
30
|
-
if (pauseOnHidden) {
|
|
31
|
-
const onVisibility = () => { paused = document.hidden; };
|
|
32
|
-
document.addEventListener("visibilitychange", onVisibility);
|
|
33
|
-
visibilityCleanup = () => document.removeEventListener("visibilitychange", onVisibility);
|
|
34
|
-
}
|
|
35
|
-
function frame(nowMs) {
|
|
36
|
-
if (paused) {
|
|
37
|
-
lastTime = nowMs;
|
|
38
|
-
reqId = requestAnimationFrame(frame);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const elapsed = Math.min(nowMs - lastTime, maxDelta);
|
|
42
|
-
lastTime = nowMs;
|
|
43
|
-
if (tickRate === "variable") {
|
|
44
|
-
clearFrameKeyboard();
|
|
45
|
-
clearFramePointer();
|
|
46
|
-
update(elapsed);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
accumulator += elapsed;
|
|
50
|
-
let ticked = false;
|
|
51
|
-
while (accumulator >= tickRate) {
|
|
52
|
-
if (!ticked) {
|
|
53
|
-
clearFrameKeyboard();
|
|
54
|
-
clearFramePointer();
|
|
55
|
-
ticked = true;
|
|
56
|
-
}
|
|
57
|
-
update(tickRate);
|
|
58
|
-
accumulator -= tickRate;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
render();
|
|
62
|
-
reqId = requestAnimationFrame(frame);
|
|
63
|
-
}
|
|
64
|
-
reqId = requestAnimationFrame(frame);
|
|
65
|
-
return {
|
|
66
|
-
stop: () => {
|
|
67
|
-
if (reqId !== null) {
|
|
68
|
-
cancelAnimationFrame(reqId);
|
|
69
|
-
reqId = null;
|
|
70
|
-
}
|
|
71
|
-
visibilityCleanup?.();
|
|
72
|
-
},
|
|
73
|
-
pause: () => { paused = true; },
|
|
74
|
-
resume: () => { paused = false; },
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
//# sourceMappingURL=update.js.map
|
package/dist/update.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"update.js","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"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"}
|
package/dist/validate.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare function isObj(x: unknown): x is Record<string, unknown>;
|
|
2
|
-
export declare function optBool(obj: Record<string, unknown>, key: string, ctx: string): boolean | undefined;
|
|
3
|
-
export declare function num(obj: Record<string, unknown>, key: string, ctx: string): number;
|
|
4
|
-
export declare function optNum(obj: Record<string, unknown>, key: string, ctx: string): number | undefined;
|
|
5
|
-
export declare function str(obj: Record<string, unknown>, key: string, ctx: string): string;
|
|
6
|
-
export declare function optStr(obj: Record<string, unknown>, key: string, ctx: string): string | undefined;
|
|
7
|
-
export declare function arr(obj: Record<string, unknown>, key: string, ctx: string): unknown[];
|
|
8
|
-
export declare function makeCollector(): {
|
|
9
|
-
errors: string[];
|
|
10
|
-
tryGet: <T>(fn: () => T) => T | undefined;
|
|
11
|
-
};
|
|
12
|
-
export type Collector = ReturnType<typeof makeCollector>;
|
|
13
|
-
//# sourceMappingURL=validate.d.ts.map
|
package/dist/validate.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9D;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAKnG;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAMlF;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOjG;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAMlF;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOjG;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,EAAE,CAIrF;AAED,wBAAgB,aAAa;;aAIhB,CAAC,MAAM,MAAM,CAAC,KAAG,CAAC,GAAG,SAAS;EAI1C;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC"}
|