1681-engine 0.5.9 → 0.6.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/CHANGELOG.md +92 -1
- package/README.md +15 -6
- package/dist/1681-engine.js +588 -465
- package/dist/ai/behaviorTree.js +198 -0
- package/dist/ai/buildTree.js +54 -0
- package/dist/ambient/life/Birds.js +73 -0
- package/dist/ambient/life/Butterflies.js +43 -0
- package/dist/ambient/life/ChimneySmoke.js +50 -0
- package/dist/ambient/life/Drift.js +75 -0
- package/dist/ambient/life/Fireflies.js +52 -0
- package/dist/ambient/life/lifeMotion.js +49 -0
- package/dist/assets/AssetLoader.js +115 -70
- package/dist/assets/Prepainter.js +61 -0
- package/dist/assets/workerPainter.js +39 -0
- package/dist/audio/spatial.js +118 -0
- package/dist/cjs/electron/electronLike.d.ts +55 -0
- package/dist/cjs/electron/electronLike.js +7 -0
- package/dist/cjs/electron/index.d.ts +14 -0
- package/dist/cjs/electron/index.js +20 -0
- package/dist/cjs/electron/lockdown.d.ts +33 -0
- package/dist/cjs/electron/lockdown.js +69 -0
- package/dist/cjs/electron/lockdownRules.d.ts +28 -0
- package/dist/cjs/electron/lockdownRules.js +61 -0
- package/dist/cjs/electron/sessionStore.d.ts +40 -0
- package/dist/cjs/electron/sessionStore.js +77 -0
- package/dist/cjs/electron/shellId.d.ts +22 -0
- package/dist/cjs/electron/shellId.js +31 -0
- package/dist/cjs/electron/webFiles.d.ts +13 -0
- package/dist/cjs/electron/webFiles.js +52 -0
- package/dist/cjs/electron/webPatcher.d.ts +83 -0
- package/dist/cjs/electron/webPatcher.js +223 -0
- package/dist/cjs/electron/webPointers.d.ts +19 -0
- package/dist/cjs/electron/webPointers.js +35 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/updates/index.d.ts +8 -0
- package/dist/cjs/updates/index.js +21 -0
- package/dist/cjs/updates/manifest.d.ts +73 -0
- package/dist/cjs/updates/manifest.js +67 -0
- package/dist/cjs/updates/pickUpdate.d.ts +42 -0
- package/dist/cjs/updates/pickUpdate.js +52 -0
- package/dist/cjs/updates/webPlan.d.ts +20 -0
- package/dist/cjs/updates/webPlan.js +34 -0
- package/dist/dialogue/DialogueRunner.js +173 -0
- package/dist/dialogue/expr.js +137 -0
- package/dist/dialogue/validateDialogue.js +52 -0
- package/dist/ecs/prefab.js +94 -0
- package/dist/electron/lockdown.js +31 -0
- package/dist/electron/lockdownRules.js +42 -0
- package/dist/electron/sessionStore.js +48 -0
- package/dist/electron/shellId.js +18 -0
- package/dist/electron/webFiles.js +36 -0
- package/dist/electron/webPatcher.js +153 -0
- package/dist/electron/webPointers.js +25 -0
- package/dist/electron.js +19 -0
- package/dist/input/Actions.js +58 -27
- package/dist/input/InputCapture.js +98 -0
- package/dist/input/Keymap.js +32 -26
- package/dist/input/haptics.js +50 -0
- package/dist/input/inputTape.js +68 -0
- package/dist/mobile/backButton.js +40 -0
- package/dist/mobile/capacitor.js +48 -0
- package/dist/mobile/screen.js +31 -0
- package/dist/mobile.js +12 -0
- package/dist/nav/flowField.js +58 -0
- package/dist/nav/steering.js +77 -0
- package/dist/net/ApiClient.js +96 -0
- package/dist/net/InterpolationBuffer.js +30 -23
- package/dist/net/LagCompensator.js +100 -0
- package/dist/net/Room.js +122 -43
- package/dist/net/RoomHost.js +13 -4
- package/dist/net/SpatialHash.js +66 -0
- package/dist/pixel/lifeArt.js +83 -0
- package/dist/pixel.js +63 -58
- package/dist/react/ConfirmButton.js +24 -0
- package/dist/react/baseCss.js +1 -0
- package/dist/react/labels.js +7 -6
- package/dist/react/useJsonSelector.js +13 -0
- package/dist/react.js +73 -68
- package/dist/tilemap/TilemapView.js +57 -32
- package/dist/tilemap/autotile.js +103 -0
- package/dist/tilemap/collision.js +29 -18
- package/dist/tilemap/ldtk.js +21 -0
- package/dist/tilemap/ldtkParse.js +191 -0
- package/dist/types/ai/behaviorTree.d.ts +133 -0
- package/dist/types/ai/behaviorTree.d.ts.map +1 -0
- package/dist/types/ai/buildTree.d.ts +55 -0
- package/dist/types/ai/buildTree.d.ts.map +1 -0
- package/dist/types/ambient/life/Birds.d.ts +50 -0
- package/dist/types/ambient/life/Birds.d.ts.map +1 -0
- package/dist/types/ambient/life/Butterflies.d.ts +32 -0
- package/dist/types/ambient/life/Butterflies.d.ts.map +1 -0
- package/dist/types/ambient/life/ChimneySmoke.d.ts +37 -0
- package/dist/types/ambient/life/ChimneySmoke.d.ts.map +1 -0
- package/dist/types/ambient/life/Drift.d.ts +58 -0
- package/dist/types/ambient/life/Drift.d.ts.map +1 -0
- package/dist/types/ambient/life/Fireflies.d.ts +43 -0
- package/dist/types/ambient/life/Fireflies.d.ts.map +1 -0
- package/dist/types/ambient/life/lifeMotion.d.ts +63 -0
- package/dist/types/ambient/life/lifeMotion.d.ts.map +1 -0
- package/dist/types/assets/AssetLoader.d.ts +20 -0
- package/dist/types/assets/AssetLoader.d.ts.map +1 -1
- package/dist/types/assets/Prepainter.d.ts +64 -0
- package/dist/types/assets/Prepainter.d.ts.map +1 -0
- package/dist/types/assets/workerPainter.d.ts +21 -0
- package/dist/types/assets/workerPainter.d.ts.map +1 -0
- package/dist/types/audio/spatial.d.ts +107 -0
- package/dist/types/audio/spatial.d.ts.map +1 -0
- package/dist/types/dialogue/DialogueRunner.d.ts +78 -0
- package/dist/types/dialogue/DialogueRunner.d.ts.map +1 -0
- package/dist/types/dialogue/expr.d.ts +12 -0
- package/dist/types/dialogue/expr.d.ts.map +1 -0
- package/dist/types/dialogue/script.d.ts +78 -0
- package/dist/types/dialogue/script.d.ts.map +1 -0
- package/dist/types/dialogue/validateDialogue.d.ts +21 -0
- package/dist/types/dialogue/validateDialogue.d.ts.map +1 -0
- package/dist/types/ecs/prefab.d.ts +84 -0
- package/dist/types/ecs/prefab.d.ts.map +1 -0
- package/dist/types/electron/electronLike.d.ts +56 -0
- package/dist/types/electron/electronLike.d.ts.map +1 -0
- package/dist/types/electron/index.d.ts +15 -0
- package/dist/types/electron/index.d.ts.map +1 -0
- package/dist/types/electron/lockdown.d.ts +34 -0
- package/dist/types/electron/lockdown.d.ts.map +1 -0
- package/dist/types/electron/lockdownRules.d.ts +29 -0
- package/dist/types/electron/lockdownRules.d.ts.map +1 -0
- package/dist/types/electron/sessionStore.d.ts +41 -0
- package/dist/types/electron/sessionStore.d.ts.map +1 -0
- package/dist/types/electron/shellId.d.ts +23 -0
- package/dist/types/electron/shellId.d.ts.map +1 -0
- package/dist/types/electron/webFiles.d.ts +14 -0
- package/dist/types/electron/webFiles.d.ts.map +1 -0
- package/dist/types/electron/webPatcher.d.ts +84 -0
- package/dist/types/electron/webPatcher.d.ts.map +1 -0
- package/dist/types/electron/webPointers.d.ts +20 -0
- package/dist/types/electron/webPointers.d.ts.map +1 -0
- package/dist/types/index.d.ts +30 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/input/Actions.d.ts +14 -0
- package/dist/types/input/Actions.d.ts.map +1 -1
- package/dist/types/input/InputCapture.d.ts +53 -0
- package/dist/types/input/InputCapture.d.ts.map +1 -0
- package/dist/types/input/Keymap.d.ts +12 -6
- package/dist/types/input/Keymap.d.ts.map +1 -1
- package/dist/types/input/haptics.d.ts +42 -0
- package/dist/types/input/haptics.d.ts.map +1 -0
- package/dist/types/input/inputTape.d.ts +66 -0
- package/dist/types/input/inputTape.d.ts.map +1 -0
- package/dist/types/mobile/backButton.d.ts +30 -0
- package/dist/types/mobile/backButton.d.ts.map +1 -0
- package/dist/types/mobile/capacitor.d.ts +62 -0
- package/dist/types/mobile/capacitor.d.ts.map +1 -0
- package/dist/types/mobile/index.d.ts +4 -0
- package/dist/types/mobile/index.d.ts.map +1 -0
- package/dist/types/mobile/screen.d.ts +27 -0
- package/dist/types/mobile/screen.d.ts.map +1 -0
- package/dist/types/nav/flowField.d.ts +31 -0
- package/dist/types/nav/flowField.d.ts.map +1 -0
- package/dist/types/nav/steering.d.ts +47 -0
- package/dist/types/nav/steering.d.ts.map +1 -0
- package/dist/types/net/ApiClient.d.ts +74 -0
- package/dist/types/net/ApiClient.d.ts.map +1 -0
- package/dist/types/net/InterpolationBuffer.d.ts +5 -0
- package/dist/types/net/InterpolationBuffer.d.ts.map +1 -1
- package/dist/types/net/LagCompensator.d.ts +70 -0
- package/dist/types/net/LagCompensator.d.ts.map +1 -0
- package/dist/types/net/Room.d.ts +72 -3
- package/dist/types/net/Room.d.ts.map +1 -1
- package/dist/types/net/RoomHost.d.ts +8 -3
- package/dist/types/net/RoomHost.d.ts.map +1 -1
- package/dist/types/net/SpatialHash.d.ts +25 -0
- package/dist/types/net/SpatialHash.d.ts.map +1 -0
- package/dist/types/pixel/index.d.ts +1 -0
- package/dist/types/pixel/index.d.ts.map +1 -1
- package/dist/types/pixel/lifeArt.d.ts +63 -0
- package/dist/types/pixel/lifeArt.d.ts.map +1 -0
- package/dist/types/react/ConfirmButton.d.ts +26 -0
- package/dist/types/react/ConfirmButton.d.ts.map +1 -0
- package/dist/types/react/baseCss.d.ts +1 -1
- package/dist/types/react/baseCss.d.ts.map +1 -1
- package/dist/types/react/index.d.ts +2 -0
- package/dist/types/react/index.d.ts.map +1 -1
- package/dist/types/react/labels.d.ts +2 -0
- package/dist/types/react/labels.d.ts.map +1 -1
- package/dist/types/react/useJsonSelector.d.ts +13 -0
- package/dist/types/react/useJsonSelector.d.ts.map +1 -0
- package/dist/types/tilemap/TilemapView.d.ts +17 -0
- package/dist/types/tilemap/TilemapView.d.ts.map +1 -1
- package/dist/types/tilemap/autotile.d.ts +95 -0
- package/dist/types/tilemap/autotile.d.ts.map +1 -0
- package/dist/types/tilemap/collision.d.ts +8 -0
- package/dist/types/tilemap/collision.d.ts.map +1 -1
- package/dist/types/tilemap/ldtk.d.ts +97 -0
- package/dist/types/tilemap/ldtk.d.ts.map +1 -0
- package/dist/types/tilemap/ldtkParse.d.ts +26 -0
- package/dist/types/tilemap/ldtkParse.d.ts.map +1 -0
- package/dist/types/ui/ScrollView.d.ts.map +1 -1
- package/dist/types/updates/index.d.ts +9 -0
- package/dist/types/updates/index.d.ts.map +1 -0
- package/dist/types/updates/manifest.d.ts +74 -0
- package/dist/types/updates/manifest.d.ts.map +1 -0
- package/dist/types/updates/pickUpdate.d.ts +43 -0
- package/dist/types/updates/pickUpdate.d.ts.map +1 -0
- package/dist/types/updates/webPlan.d.ts +21 -0
- package/dist/types/updates/webPlan.d.ts.map +1 -0
- package/dist/ui/ScrollView.js +10 -8
- package/dist/updates/manifest.js +35 -0
- package/dist/updates/pickUpdate.js +27 -0
- package/dist/updates/webPlan.js +14 -0
- package/dist/updates.js +15 -0
- package/package.json +35 -3
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { existsSync as b } from "node:fs";
|
|
2
|
+
import { rm as d, mkdir as M, readFile as V, rename as T, readdir as x } from "node:fs/promises";
|
|
3
|
+
import { join as s } from "node:path";
|
|
4
|
+
import { isNewer as y, validManifest as $, fileUrl as P } from "../updates/manifest.js";
|
|
5
|
+
import { planWeb as U } from "../updates/webPlan.js";
|
|
6
|
+
import { fetchWithTimeout as u, hashWeb as D, putFile as g, sha256 as E } from "./webFiles.js";
|
|
7
|
+
import { WebPointers as W } from "./webPointers.js";
|
|
8
|
+
class z {
|
|
9
|
+
constructor(e) {
|
|
10
|
+
this.options = e, this.o = {
|
|
11
|
+
root: e.root,
|
|
12
|
+
builtinDir: e.builtinDir,
|
|
13
|
+
appVersion: e.appVersion,
|
|
14
|
+
channelUrl: e.channelUrl,
|
|
15
|
+
packaged: e.packaged ?? !0,
|
|
16
|
+
maxTries: e.maxTries ?? 2,
|
|
17
|
+
keepPrevious: e.keepPrevious ?? !0,
|
|
18
|
+
entry: e.entry ?? "index.html",
|
|
19
|
+
parallel: e.parallel ?? 6,
|
|
20
|
+
fetchTimeoutMs: e.fetchTimeoutMs ?? 15e3,
|
|
21
|
+
fetch: e.fetch ?? ((t, i) => globalThis.fetch(t, i)),
|
|
22
|
+
log: e.log ?? ((...t) => console.error(...t))
|
|
23
|
+
}, this.pointers = new W(e.root);
|
|
24
|
+
}
|
|
25
|
+
options;
|
|
26
|
+
o;
|
|
27
|
+
pointers;
|
|
28
|
+
shellValue = null;
|
|
29
|
+
/** The web this run loads, and its version (the installed build's own when none is patched in). */
|
|
30
|
+
loaded = null;
|
|
31
|
+
/** The tidy a start began: a build waits for it, or it could delete the `.part` folder being filled. */
|
|
32
|
+
tidying = Promise.resolve();
|
|
33
|
+
tidyChain = Promise.resolve();
|
|
34
|
+
/** This shell's identity. */
|
|
35
|
+
get shell() {
|
|
36
|
+
const e = this.options.shell;
|
|
37
|
+
return this.shellValue ??= typeof e == "string" ? e : e(), this.shellValue;
|
|
38
|
+
}
|
|
39
|
+
/** Where the window loads the page from: a patched web when there is a good one, else the built-in copy. */
|
|
40
|
+
startEntry() {
|
|
41
|
+
if (!this.o.packaged)
|
|
42
|
+
return this.loaded = { dir: this.o.builtinDir, version: this.o.appVersion }, s(this.o.builtinDir, this.o.entry);
|
|
43
|
+
try {
|
|
44
|
+
const e = this.pointers.read("pending");
|
|
45
|
+
this.usable(e) && this.promote(e, 0), this.pointers.write("pending", null);
|
|
46
|
+
const t = this.pointers.read("active");
|
|
47
|
+
if (this.usable(t) && (t.booted || t.tries < this.o.maxTries))
|
|
48
|
+
t.booted || this.pointers.write("active", { ...t, tries: t.tries + 1 }), this.loaded = { dir: s(this.o.root, t.version), version: t.version };
|
|
49
|
+
else {
|
|
50
|
+
t && this.pointers.write("active", null);
|
|
51
|
+
const i = this.pointers.read("previous");
|
|
52
|
+
this.pointers.write("previous", null), this.o.keepPrevious && i?.booted && this.usable(i) && (this.pointers.write("active", i), this.loaded = { dir: s(this.o.root, i.version), version: i.version });
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
this.o.log("[web] could not read the patched web, using the built-in one", e);
|
|
56
|
+
}
|
|
57
|
+
return this.loaded ??= { dir: this.o.builtinDir, version: this.o.appVersion }, this.tidying = this.tidy(), s(this.loaded.dir, this.o.entry);
|
|
58
|
+
}
|
|
59
|
+
/** The version of the web running now. */
|
|
60
|
+
webVersion() {
|
|
61
|
+
return this.loaded?.version ?? this.o.appVersion;
|
|
62
|
+
}
|
|
63
|
+
/** The page came up: the web it was loaded from is kept from now on. Call it from the page's own "booted" message. */
|
|
64
|
+
markBooted() {
|
|
65
|
+
const e = this.pointers.read("active");
|
|
66
|
+
e && this.loaded && e.version === this.loaded.version && !e.booted && this.pointers.write("active", { ...e, booted: !0 });
|
|
67
|
+
}
|
|
68
|
+
/** The channel's newest build, or null when the store cannot be read. */
|
|
69
|
+
async latest() {
|
|
70
|
+
try {
|
|
71
|
+
const e = await u(this.o.fetch, `${this.o.channelUrl}/latest.json`, this.o.fetchTimeoutMs);
|
|
72
|
+
if (!e.ok) return null;
|
|
73
|
+
const t = await e.json();
|
|
74
|
+
return typeof t?.version == "string" ? t : null;
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Whether `l`'s web can be patched in here rather than installed: newer than the web running, for this shell. */
|
|
80
|
+
patchable(e) {
|
|
81
|
+
return !!e.web && e.web.shell === this.shell && y(e.version, this.webVersion());
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Builds `l`'s web beside the one running: the files held are copied, the rest downloaded and checked, into
|
|
85
|
+
* `<version>.part/`, which becomes `<version>/` and the pending web once whole — a crash mid-way never leaves a
|
|
86
|
+
* folder that looks finished. `onProgress` gets 0–100. Resolves with the version built; throws on any failure.
|
|
87
|
+
*/
|
|
88
|
+
async prepare(e, t = () => {
|
|
89
|
+
}) {
|
|
90
|
+
if (!e.web) throw new Error("no web in this release");
|
|
91
|
+
const i = await u(this.o.fetch, `${this.o.channelUrl}/${e.web.manifest}`, this.o.fetchTimeoutMs);
|
|
92
|
+
if (!i.ok) throw new Error(`web manifest ${i.status}`);
|
|
93
|
+
const o = await i.json();
|
|
94
|
+
if (!$(o) || o.version !== e.version || o.shell !== this.shell) throw new Error("bad web manifest");
|
|
95
|
+
const l = s(this.o.root, o.version), p = { version: o.version, shell: o.shell, booted: !1, tries: 0 };
|
|
96
|
+
if (b(s(l, this.o.entry)) && this.pointers.read("active")?.version !== o.version)
|
|
97
|
+
return this.pointers.write("pending", p), t(100), o.version;
|
|
98
|
+
await this.tidying;
|
|
99
|
+
const f = this.loaded?.dir ?? this.o.builtinDir, h = U(o, await D(f)), n = s(this.o.root, `${o.version}.part`);
|
|
100
|
+
await d(n, { recursive: !0, force: !0 }), await M(n, { recursive: !0 });
|
|
101
|
+
for (const r of h.copy) await g(n, r.path, await V(s(f, ...r.from.split("/"))));
|
|
102
|
+
let v = 0;
|
|
103
|
+
const w = /* @__PURE__ */ new Map(), m = [...h.download];
|
|
104
|
+
t(h.bytes ? 0 : 100);
|
|
105
|
+
const k = async () => {
|
|
106
|
+
for (let r = m.shift(); r; r = m.shift()) {
|
|
107
|
+
let a = w.get(r.sha256);
|
|
108
|
+
if (!a) {
|
|
109
|
+
const c = await u(this.o.fetch, P(this.o.channelUrl, r.sha256), this.o.fetchTimeoutMs);
|
|
110
|
+
if (!c.ok) throw new Error(`${r.path}: ${c.status}`);
|
|
111
|
+
if (a = new Uint8Array(await c.arrayBuffer()), E(a) !== r.sha256) throw new Error(`${r.path}: checksum`);
|
|
112
|
+
w.set(r.sha256, a), v += r.size, t(Math.min(99, Math.round(v / Math.max(1, h.bytes) * 100)));
|
|
113
|
+
}
|
|
114
|
+
await g(n, r.path, a);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
return await Promise.all(Array.from({ length: Math.max(1, this.o.parallel) }, k)), await d(l, { recursive: !0, force: !0 }), await T(n, l), this.pointers.write("pending", p), t(100), o.version;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Puts the pending web in use now and returns the page to load (reload every window from it), or null when there is
|
|
121
|
+
* none this shell may load. The switch counts as its first start, so a web that never boots is still dropped.
|
|
122
|
+
*/
|
|
123
|
+
applyPending() {
|
|
124
|
+
const e = this.pointers.read("pending");
|
|
125
|
+
return this.usable(e) ? (this.promote(e, 1), this.pointers.write("pending", null), this.loaded = { dir: s(this.o.root, e.version), version: e.version }, s(this.loaded.dir, this.o.entry)) : null;
|
|
126
|
+
}
|
|
127
|
+
/** Makes `p` the active web, keeping the one it replaces as the fallback when that one ever booted. */
|
|
128
|
+
promote(e, t) {
|
|
129
|
+
const i = this.pointers.read("active");
|
|
130
|
+
this.o.keepPrevious && i?.booted && i.version !== e.version && this.pointers.write("previous", i), this.pointers.write("active", { ...e, booted: !1, tries: t });
|
|
131
|
+
}
|
|
132
|
+
/** A pointer this shell may load: its own shell, newer than the installed build, its folder whole. */
|
|
133
|
+
usable(e) {
|
|
134
|
+
return !!e && e.shell === this.shell && y(e.version, this.o.appVersion) && b(s(this.o.root, e.version, this.o.entry));
|
|
135
|
+
}
|
|
136
|
+
/** Removes every patched web but the active, pending and previous one, and any half-made folder. A call made while
|
|
137
|
+
* one is running waits for it and then runs once more, so two never delete the same folder at once. */
|
|
138
|
+
tidy() {
|
|
139
|
+
const e = this.tidyChain.then(() => this.tidyOnce());
|
|
140
|
+
return this.tidyChain = e, e;
|
|
141
|
+
}
|
|
142
|
+
async tidyOnce() {
|
|
143
|
+
try {
|
|
144
|
+
const e = ["active", "pending", "previous"], t = new Set([...e.map((i) => this.pointers.read(i)?.version), this.loaded?.version].filter((i) => !!i));
|
|
145
|
+
for (const i of await x(this.o.root))
|
|
146
|
+
i.endsWith(".json") || t.has(i) || await d(s(this.o.root, i), { recursive: !0, force: !0 });
|
|
147
|
+
} catch {
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export {
|
|
152
|
+
z as WebPatcher
|
|
153
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readFileSync as t, mkdirSync as i, writeFileSync as o, rmSync as s } from "node:fs";
|
|
2
|
+
import { join as n } from "node:path";
|
|
3
|
+
class c {
|
|
4
|
+
constructor(e) {
|
|
5
|
+
this.root = e;
|
|
6
|
+
}
|
|
7
|
+
root;
|
|
8
|
+
read(e) {
|
|
9
|
+
try {
|
|
10
|
+
const r = JSON.parse(t(this.file(e), "utf8"));
|
|
11
|
+
return typeof r?.version != "string" || typeof r.shell != "string" ? null : { version: r.version, shell: r.shell, booted: r.booted === !0, tries: typeof r.tries == "number" ? r.tries : 0 };
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
write(e, r) {
|
|
17
|
+
r ? (i(this.root, { recursive: !0 }), o(this.file(e), JSON.stringify(r))) : s(this.file(e), { force: !0 });
|
|
18
|
+
}
|
|
19
|
+
file(e) {
|
|
20
|
+
return n(this.root, `${e}.json`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
c as WebPointers
|
|
25
|
+
};
|
package/dist/electron.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { shellId as r } from "./electron/shellId.js";
|
|
2
|
+
import { WebPatcher as t } from "./electron/webPatcher.js";
|
|
3
|
+
import { SessionStore as l, registerSessionStore as n } from "./electron/sessionStore.js";
|
|
4
|
+
import { DEBUG_SWITCHES as f, debuggerRequested as m, isAllowedExternal as x, isAllowedNavigation as S, isDevToolsKey as a } from "./electron/lockdownRules.js";
|
|
5
|
+
import { denyPermissions as p, lockDownWindow as u, refuseDebugLaunch as w } from "./electron/lockdown.js";
|
|
6
|
+
export {
|
|
7
|
+
f as DEBUG_SWITCHES,
|
|
8
|
+
l as SessionStore,
|
|
9
|
+
t as WebPatcher,
|
|
10
|
+
m as debuggerRequested,
|
|
11
|
+
p as denyPermissions,
|
|
12
|
+
x as isAllowedExternal,
|
|
13
|
+
S as isAllowedNavigation,
|
|
14
|
+
a as isDevToolsKey,
|
|
15
|
+
u as lockDownWindow,
|
|
16
|
+
w as refuseDebugLaunch,
|
|
17
|
+
n as registerSessionStore,
|
|
18
|
+
r as shellId
|
|
19
|
+
};
|
package/dist/input/Actions.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { parseChord as c, chordHeld as l } from "./keyChord.js";
|
|
2
2
|
import { rumblePad as f } from "./rumble.js";
|
|
3
3
|
const u = ["a", "b", "x", "y", "lb", "rb", "lt", "rt", "select", "start", "ls", "rs", "up", "down", "left", "right", "home"], w = ["lx", "ly", "rx", "ry"];
|
|
4
|
-
class
|
|
5
|
-
constructor(t,
|
|
6
|
-
this.keyboard = t, this.bindings = new Map(Object.entries(
|
|
4
|
+
class v {
|
|
5
|
+
constructor(t, s, e = {}) {
|
|
6
|
+
this.keyboard = t, this.bindings = new Map(Object.entries(s)), this.deadZone = e.deadZone ?? 0.25, this.gamepads = e.gamepads ?? (() => typeof navigator < "u" && typeof navigator.getGamepads == "function" ? navigator.getGamepads() : []);
|
|
7
7
|
}
|
|
8
8
|
keyboard;
|
|
9
9
|
bindings;
|
|
@@ -18,10 +18,14 @@ class g {
|
|
|
18
18
|
chords = /* @__PURE__ */ new Map();
|
|
19
19
|
/** Keys a chord holds this step: their bare bindings read 0 until the key comes up. */
|
|
20
20
|
claimed = /* @__PURE__ */ new Set();
|
|
21
|
+
/** Where `poll` takes its values from instead of the devices (a replay), until it returns null. */
|
|
22
|
+
source = null;
|
|
23
|
+
/** Handed every step's values after `poll` (a recorder). */
|
|
24
|
+
taps = /* @__PURE__ */ new Set();
|
|
21
25
|
keyDown = (t) => this.keyboard !== null && (this.keyboard.isDown(t) || this.keyboard.pressed(t));
|
|
22
26
|
/** Replaces one action's bindings (a player's rebinding). */
|
|
23
|
-
bind(t,
|
|
24
|
-
this.bindings.set(t, [...
|
|
27
|
+
bind(t, s) {
|
|
28
|
+
this.bindings.set(t, [...s]);
|
|
25
29
|
}
|
|
26
30
|
bindingsOf(t) {
|
|
27
31
|
return this.bindings.get(t) ?? [];
|
|
@@ -37,19 +41,46 @@ class g {
|
|
|
37
41
|
* Rumbles the gamepads the actions read: every connected one, or only `padIndex` among them. Resolves true when any
|
|
38
42
|
* played; a pad without rumble is skipped silently.
|
|
39
43
|
*/
|
|
40
|
-
async rumble(t,
|
|
41
|
-
const
|
|
44
|
+
async rumble(t, s) {
|
|
45
|
+
const e = this.gamepads(), i = s === void 0 ? e : [e[s] ?? null];
|
|
42
46
|
return (await Promise.all(i.map((r) => r ? f(r, t) : Promise.resolve(!1)))).includes(!0);
|
|
43
47
|
}
|
|
44
48
|
/** Reads every device once; call at the start of each simulation step. */
|
|
45
49
|
poll() {
|
|
46
|
-
[this.before, this.now] = [this.now, this.before], this.now.clear()
|
|
47
|
-
|
|
50
|
+
if ([this.before, this.now] = [this.now, this.before], this.now.clear(), this.source) {
|
|
51
|
+
const t = this.source();
|
|
52
|
+
if (t) {
|
|
53
|
+
for (const [s, e] of t) e > 0 && this.now.set(s, e);
|
|
54
|
+
for (const s of this.taps) s(this.now);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.source = null;
|
|
58
|
+
}
|
|
59
|
+
this.readDevices();
|
|
60
|
+
for (const t of this.taps) t(this.now);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Takes each step's values from `source` instead of the devices (an `InputPlayer`), until it returns null; then
|
|
64
|
+
* the devices answer again. Pass null to stop at once.
|
|
65
|
+
*/
|
|
66
|
+
replay(t) {
|
|
67
|
+
this.source = t;
|
|
68
|
+
}
|
|
69
|
+
/** Whether a replay is driving the actions now. */
|
|
70
|
+
get replaying() {
|
|
71
|
+
return this.source !== null;
|
|
72
|
+
}
|
|
73
|
+
/** Calls `tap` with every step's values right after `poll` (an `InputRecorder`); returns the stop. */
|
|
74
|
+
tap(t) {
|
|
75
|
+
return this.taps.add(t), () => this.taps.delete(t);
|
|
76
|
+
}
|
|
77
|
+
readDevices() {
|
|
78
|
+
const t = this.gamepads().filter((s) => s !== null);
|
|
48
79
|
this.claimChords();
|
|
49
|
-
for (const [
|
|
80
|
+
for (const [s, e] of this.bindings) {
|
|
50
81
|
let i = 0;
|
|
51
|
-
for (const o of
|
|
52
|
-
i > 0 && this.now.set(
|
|
82
|
+
for (const o of e) i = Math.max(i, this.read(o, t));
|
|
83
|
+
i > 0 && this.now.set(s, i);
|
|
53
84
|
}
|
|
54
85
|
}
|
|
55
86
|
/** Held this step. */
|
|
@@ -69,12 +100,12 @@ class g {
|
|
|
69
100
|
return !this.down(t) && (this.before.get(t) ?? 0) > 0;
|
|
70
101
|
}
|
|
71
102
|
/** `value(positive) - value(negative)`, in −1…1. */
|
|
72
|
-
axis(t,
|
|
73
|
-
return this.value(
|
|
103
|
+
axis(t, s) {
|
|
104
|
+
return this.value(s) - this.value(t);
|
|
74
105
|
}
|
|
75
106
|
/** A 2D direction from four actions, never longer than 1 (a diagonal is not faster). */
|
|
76
|
-
vector(t,
|
|
77
|
-
const o = this.axis(t,
|
|
107
|
+
vector(t, s, e, i) {
|
|
108
|
+
const o = this.axis(t, s), r = this.axis(e, i), n = Math.hypot(o, r);
|
|
78
109
|
return n > 1 ? [o / n, r / n] : [o, r];
|
|
79
110
|
}
|
|
80
111
|
/** Ends the step: the keyboard forgets its edges; virtual taps shorter than a step have now been seen. */
|
|
@@ -90,20 +121,20 @@ class g {
|
|
|
90
121
|
this.keyboard?.endStep(), this.virtualDown.clear(), this.poll(), this.before = new Map(this.now);
|
|
91
122
|
}
|
|
92
123
|
chordOf(t) {
|
|
93
|
-
let
|
|
94
|
-
return
|
|
124
|
+
let s = this.chords.get(t);
|
|
125
|
+
return s === void 0 && (s = t.startsWith("pad:") || t.startsWith("touch:") ? null : c(t), this.chords.set(t, s)), s;
|
|
95
126
|
}
|
|
96
127
|
/** Marks the keys held chords use, and frees those whose key has come up. */
|
|
97
128
|
claimChords() {
|
|
98
129
|
for (const t of this.claimed) this.keyDown(t) || this.claimed.delete(t);
|
|
99
130
|
if (this.keyboard)
|
|
100
131
|
for (const t of this.bindings.values())
|
|
101
|
-
for (const
|
|
102
|
-
const
|
|
103
|
-
|
|
132
|
+
for (const s of t) {
|
|
133
|
+
const e = this.chordOf(s);
|
|
134
|
+
e && l(e, this.keyDown) && this.claimed.add(e.code);
|
|
104
135
|
}
|
|
105
136
|
}
|
|
106
|
-
read(t,
|
|
137
|
+
read(t, s) {
|
|
107
138
|
if (t.startsWith("touch:")) {
|
|
108
139
|
const i = t.slice(6);
|
|
109
140
|
return this.virtual.has(i) || this.virtualDown.has(i) ? 1 : 0;
|
|
@@ -115,7 +146,7 @@ class g {
|
|
|
115
146
|
if (r !== 0) {
|
|
116
147
|
const h = w.indexOf(i.slice(0, -1));
|
|
117
148
|
if (h < 0) return 0;
|
|
118
|
-
for (const a of
|
|
149
|
+
for (const a of s) {
|
|
119
150
|
const d = (a.axes[h] ?? 0) * r;
|
|
120
151
|
d > this.deadZone && (o = Math.max(o, (d - this.deadZone) / (1 - this.deadZone)));
|
|
121
152
|
}
|
|
@@ -123,17 +154,17 @@ class g {
|
|
|
123
154
|
}
|
|
124
155
|
const n = u.indexOf(i);
|
|
125
156
|
if (n < 0) return 0;
|
|
126
|
-
for (const h of
|
|
157
|
+
for (const h of s) {
|
|
127
158
|
const a = h.buttons[n];
|
|
128
159
|
a?.pressed && (o = Math.max(o, a.value > 0 ? a.value : 1));
|
|
129
160
|
}
|
|
130
161
|
return Math.min(1, o);
|
|
131
162
|
}
|
|
132
|
-
const
|
|
133
|
-
return
|
|
163
|
+
const e = this.chordOf(t);
|
|
164
|
+
return e ? l(e, this.keyDown) ? 1 : 0 : this.claimed.has(t) ? 0 : this.keyDown(t) ? 1 : 0;
|
|
134
165
|
}
|
|
135
166
|
}
|
|
136
167
|
export {
|
|
137
|
-
|
|
168
|
+
v as Actions,
|
|
138
169
|
u as PAD_BUTTONS
|
|
139
170
|
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { PAD_BUTTONS as r } from "./Actions.js";
|
|
2
|
+
function c(s) {
|
|
3
|
+
return s.startsWith("pad:") ? "pad" : s.startsWith("touch:") ? "touch" : "keys";
|
|
4
|
+
}
|
|
5
|
+
const h = ["lx", "ly", "rx", "ry"], a = {
|
|
6
|
+
a: "A",
|
|
7
|
+
b: "B",
|
|
8
|
+
x: "X",
|
|
9
|
+
y: "Y",
|
|
10
|
+
lb: "LB",
|
|
11
|
+
rb: "RB",
|
|
12
|
+
lt: "LT",
|
|
13
|
+
rt: "RT",
|
|
14
|
+
select: "Select",
|
|
15
|
+
start: "Start",
|
|
16
|
+
ls: "Left stick press",
|
|
17
|
+
rs: "Right stick press",
|
|
18
|
+
up: "D-pad up",
|
|
19
|
+
down: "D-pad down",
|
|
20
|
+
left: "D-pad left",
|
|
21
|
+
right: "D-pad right",
|
|
22
|
+
home: "Home",
|
|
23
|
+
"lx-": "Left stick left",
|
|
24
|
+
"lx+": "Left stick right",
|
|
25
|
+
"ly-": "Left stick up",
|
|
26
|
+
"ly+": "Left stick down",
|
|
27
|
+
"rx-": "Right stick left",
|
|
28
|
+
"rx+": "Right stick right",
|
|
29
|
+
"ry-": "Right stick up",
|
|
30
|
+
"ry+": "Right stick down"
|
|
31
|
+
};
|
|
32
|
+
function p(s, t = {}) {
|
|
33
|
+
if (!s.startsWith("pad:")) return s;
|
|
34
|
+
const e = s.slice(4);
|
|
35
|
+
return t[e] ?? a[e] ?? e;
|
|
36
|
+
}
|
|
37
|
+
class l {
|
|
38
|
+
result;
|
|
39
|
+
settle;
|
|
40
|
+
done = !1;
|
|
41
|
+
held = /* @__PURE__ */ new Set();
|
|
42
|
+
options;
|
|
43
|
+
gamepads;
|
|
44
|
+
target;
|
|
45
|
+
onKey = (t) => this.key(t);
|
|
46
|
+
constructor(t = {}) {
|
|
47
|
+
this.options = {
|
|
48
|
+
devices: t.devices ?? ["keys", "pad"],
|
|
49
|
+
ignoreKeys: t.ignoreKeys ?? ["Escape"],
|
|
50
|
+
cancelKeys: t.cancelKeys ?? ["Escape"],
|
|
51
|
+
axisThreshold: t.axisThreshold ?? 0.6
|
|
52
|
+
}, this.gamepads = t.gamepads ?? (() => typeof navigator < "u" && typeof navigator.getGamepads == "function" ? navigator.getGamepads() : []), this.target = t.target ?? (typeof window < "u" ? window : null), this.result = new Promise((e) => this.settle = e);
|
|
53
|
+
for (const e of this.padInputs()) this.held.add(e);
|
|
54
|
+
this.options.devices.includes("keys") && this.target?.addEventListener("keydown", this.onKey, { capture: !0 });
|
|
55
|
+
}
|
|
56
|
+
/** Reads the gamepads once; call every frame while the capture is open. */
|
|
57
|
+
poll() {
|
|
58
|
+
if (this.done || !this.options.devices.includes("pad")) return;
|
|
59
|
+
const t = new Set(this.padInputs());
|
|
60
|
+
for (const e of t)
|
|
61
|
+
if (!this.held.has(e))
|
|
62
|
+
return this.finish(e);
|
|
63
|
+
for (const e of [...this.held]) t.has(e) || this.held.delete(e);
|
|
64
|
+
}
|
|
65
|
+
/** Stops waiting; the result is null. */
|
|
66
|
+
cancel() {
|
|
67
|
+
this.finish(null);
|
|
68
|
+
}
|
|
69
|
+
get open() {
|
|
70
|
+
return !this.done;
|
|
71
|
+
}
|
|
72
|
+
key(t) {
|
|
73
|
+
if (!(this.done || t.repeat)) {
|
|
74
|
+
if (t.preventDefault(), t.stopImmediatePropagation(), this.options.cancelKeys.includes(t.code)) return this.finish(null);
|
|
75
|
+
this.options.ignoreKeys.includes(t.code) || !t.code || this.finish(t.code);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
finish(t) {
|
|
79
|
+
this.done || (this.done = !0, this.target?.removeEventListener("keydown", this.onKey, { capture: !0 }), this.settle(t));
|
|
80
|
+
}
|
|
81
|
+
/** Every pad input down on any pad now, as bindings. */
|
|
82
|
+
padInputs() {
|
|
83
|
+
const t = [];
|
|
84
|
+
for (const e of this.gamepads())
|
|
85
|
+
e && (e.buttons.forEach((i, n) => {
|
|
86
|
+
(i.pressed || i.value > this.options.axisThreshold) && r[n] && t.push(`pad:${r[n]}`);
|
|
87
|
+
}), h.forEach((i, n) => {
|
|
88
|
+
const o = e.axes[n] ?? 0;
|
|
89
|
+
o > this.options.axisThreshold ? t.push(`pad:${i}+`) : o < -this.options.axisThreshold && t.push(`pad:${i}-`);
|
|
90
|
+
}));
|
|
91
|
+
return t;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export {
|
|
95
|
+
l as InputCapture,
|
|
96
|
+
c as deviceOf,
|
|
97
|
+
p as padLabel
|
|
98
|
+
};
|
package/dist/input/Keymap.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { deviceOf as u } from "./InputCapture.js";
|
|
2
|
+
class p {
|
|
2
3
|
binds;
|
|
3
4
|
defaults;
|
|
4
5
|
reserved;
|
|
@@ -23,9 +24,13 @@ class g {
|
|
|
23
24
|
isReserved(t) {
|
|
24
25
|
return this.reserved.has(t);
|
|
25
26
|
}
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
/**
|
|
28
|
+
* The bindings of one action, or only those of one device; the first of a device is the one a settings screen
|
|
29
|
+
* shows and edits.
|
|
30
|
+
*/
|
|
31
|
+
keysFor(t, s) {
|
|
32
|
+
const e = this.binds[t] ?? [];
|
|
33
|
+
return s ? e.filter((h) => u(h) === s) : e;
|
|
29
34
|
}
|
|
30
35
|
/** The inputs an action always has besides the player's keys (the constructor's `fixed`). */
|
|
31
36
|
fixedFor(t) {
|
|
@@ -36,17 +41,18 @@ class g {
|
|
|
36
41
|
for (const s of this.actions()) if (this.binds[s].includes(t)) return s;
|
|
37
42
|
}
|
|
38
43
|
/**
|
|
39
|
-
* Puts `code` first on `action
|
|
40
|
-
*
|
|
41
|
-
*
|
|
44
|
+
* Puts `code` first on `action` in place of the action's first binding of the same device (a key replaces its first
|
|
45
|
+
* key, a pad input its first pad input), taking it off whatever else held it; returns the actions that lost it (to
|
|
46
|
+
* tell the player). A reserved key is refused (returns null). An action stripped of its last key keeps none: it is
|
|
47
|
+
* unbound until something is put back on it.
|
|
42
48
|
*/
|
|
43
49
|
bind(t, s) {
|
|
44
50
|
if (this.reserved.has(s) || !(t in this.binds)) return null;
|
|
45
51
|
const e = [];
|
|
46
52
|
for (const n of this.actions())
|
|
47
|
-
n === t || !this.binds[n].includes(s) || (this.binds[n] = this.binds[n].filter((
|
|
48
|
-
const h = this.binds[t].
|
|
49
|
-
return this.binds[t] = [s, ...
|
|
53
|
+
n === t || !this.binds[n].includes(s) || (this.binds[n] = this.binds[n].filter((r) => r !== s), e.push(n));
|
|
54
|
+
const h = u(s), f = this.binds[t].find((n) => u(n) === h), a = this.binds[t].filter((n) => n !== f && n !== s);
|
|
55
|
+
return this.binds[t] = [s, ...a], this.changed(), e;
|
|
50
56
|
}
|
|
51
57
|
/** Takes every key off `action`. */
|
|
52
58
|
unbind(t) {
|
|
@@ -68,7 +74,7 @@ class g {
|
|
|
68
74
|
* (the saved one is what the player chose). Anything malformed is ignored.
|
|
69
75
|
*/
|
|
70
76
|
load(t) {
|
|
71
|
-
this.binds =
|
|
77
|
+
this.binds = c(this.defaults, t, this.reserved), this.changed();
|
|
72
78
|
}
|
|
73
79
|
/**
|
|
74
80
|
* Hands the bindings to an `Actions`: each action's keys, then its fixed inputs, then its `extra` ones. Only the
|
|
@@ -90,19 +96,19 @@ class g {
|
|
|
90
96
|
for (const t of [...this.listeners]) t();
|
|
91
97
|
}
|
|
92
98
|
}
|
|
93
|
-
function
|
|
94
|
-
const e = Object.keys(i), h = {},
|
|
99
|
+
function c(i, t, s = /* @__PURE__ */ new Set()) {
|
|
100
|
+
const e = Object.keys(i), h = {}, f = /* @__PURE__ */ new Set(), a = t && typeof t == "object" ? t : {};
|
|
95
101
|
for (const r of e) {
|
|
96
102
|
const o = a[r];
|
|
97
|
-
Array.isArray(o) && o.every((
|
|
103
|
+
Array.isArray(o) && o.every((l) => typeof l == "string") ? (h[r] = [...new Set(o)].filter((l) => !s.has(l)), f.add(r)) : h[r] = i[r].filter((l) => !s.has(l));
|
|
98
104
|
}
|
|
99
|
-
const
|
|
105
|
+
const n = /* @__PURE__ */ new Map();
|
|
100
106
|
for (const r of e)
|
|
101
|
-
|
|
102
|
-
for (const r of e)
|
|
107
|
+
f.has(r) && (h[r] = h[r].filter((o) => n.has(o) ? !1 : (n.set(o, r), !0)));
|
|
108
|
+
for (const r of e) f.has(r) || (h[r] = h[r].filter((o) => !n.has(o)));
|
|
103
109
|
return h;
|
|
104
110
|
}
|
|
105
|
-
function
|
|
111
|
+
function S(i) {
|
|
106
112
|
const t = () => {
|
|
107
113
|
try {
|
|
108
114
|
return typeof localStorage > "u" ? null : localStorage;
|
|
@@ -133,7 +139,7 @@ function b(i) {
|
|
|
133
139
|
}
|
|
134
140
|
};
|
|
135
141
|
}
|
|
136
|
-
const
|
|
142
|
+
const d = {
|
|
137
143
|
Space: "Space",
|
|
138
144
|
ShiftLeft: "Shift",
|
|
139
145
|
ShiftRight: "Right Shift",
|
|
@@ -157,14 +163,14 @@ const c = {
|
|
|
157
163
|
BracketLeft: "[",
|
|
158
164
|
BracketRight: "]"
|
|
159
165
|
};
|
|
160
|
-
function
|
|
161
|
-
if (i.length > 1 && i.includes("+")) return i.split("+").map((e) =>
|
|
166
|
+
function b(i, t = {}) {
|
|
167
|
+
if (i.length > 1 && i.includes("+")) return i.split("+").map((e) => b(e, t)).join("+");
|
|
162
168
|
const s = t[i];
|
|
163
|
-
return s !== void 0 ? s : i.startsWith("Key") ? i.slice(3) : i.startsWith("Digit") ? i.slice(5) : i.startsWith("Numpad") ? `Num ${i.slice(6)}` :
|
|
169
|
+
return s !== void 0 ? s : i.startsWith("Key") ? i.slice(3) : i.startsWith("Digit") ? i.slice(5) : i.startsWith("Numpad") ? `Num ${i.slice(6)}` : d[i] ?? i;
|
|
164
170
|
}
|
|
165
171
|
export {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
172
|
+
p as Keymap,
|
|
173
|
+
b as keyLabel,
|
|
174
|
+
S as keymapStorage,
|
|
175
|
+
c as mergeKeymap
|
|
170
176
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
class n {
|
|
2
|
+
constructor(t = {}) {
|
|
3
|
+
this.gaps = t;
|
|
4
|
+
}
|
|
5
|
+
gaps;
|
|
6
|
+
last = /* @__PURE__ */ new Map();
|
|
7
|
+
/** Whether a buzz of `kind` at `now` (ms) may go; one that may is counted. */
|
|
8
|
+
allow(t, e) {
|
|
9
|
+
const r = this.last.get(t), s = this.gaps[t] ?? 0;
|
|
10
|
+
return r !== void 0 && e - r < s ? !1 : (this.last.set(t, e), !0);
|
|
11
|
+
}
|
|
12
|
+
/** Forgets every kind's last buzz. */
|
|
13
|
+
reset() {
|
|
14
|
+
this.last.clear();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function c(a) {
|
|
18
|
+
const t = typeof navigator > "u" ? void 0 : navigator;
|
|
19
|
+
if (typeof t?.vibrate != "function") return !1;
|
|
20
|
+
try {
|
|
21
|
+
return t.vibrate(typeof a == "number" ? a : [...a]);
|
|
22
|
+
} catch {
|
|
23
|
+
return !1;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
class i {
|
|
27
|
+
gate;
|
|
28
|
+
play;
|
|
29
|
+
enabled;
|
|
30
|
+
now;
|
|
31
|
+
constructor(t = {}) {
|
|
32
|
+
this.gate = new n(t.gaps), this.play = t.play ?? ((e) => c(t.patterns?.[e] ?? 15)), this.enabled = t.enabled ?? (() => !0), this.now = t.now ?? (() => performance.now());
|
|
33
|
+
}
|
|
34
|
+
/** Buzzes for `kind`; returns whether it was let through (not whether the device did buzz). */
|
|
35
|
+
buzz(t) {
|
|
36
|
+
if (!this.enabled() || !this.gate.allow(t, this.now())) return !1;
|
|
37
|
+
try {
|
|
38
|
+
const e = this.play(t);
|
|
39
|
+
e && typeof e.catch == "function" && e.catch(() => {
|
|
40
|
+
});
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
return !0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
n as HapticGate,
|
|
48
|
+
i as Haptics,
|
|
49
|
+
c as vibrate
|
|
50
|
+
};
|