cubing 0.63.2 → 0.63.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/dist/bin/chunks/{chunk-52ODPET6.js → chunk-OI3YIXMQ.js} +2 -2
- package/dist/bin/order.js +1 -1
- package/dist/bin/puzzle-geometry-bin.js +1 -1
- package/dist/bin/scramble.js +1 -1
- package/dist/lib/cubing/{PuzzleLoader-R-puDLmC.d.ts → PuzzleLoader-Bp8zngUn.d.ts} +10 -0
- package/dist/lib/cubing/alg/index.d.ts +2 -2
- package/dist/lib/cubing/bluetooth/index.d.ts +2 -2
- package/dist/lib/cubing/chunks/chunk-44CFF24P.js +239 -0
- package/dist/lib/cubing/chunks/chunk-44CFF24P.js.map +7 -0
- package/dist/lib/cubing/chunks/chunk-DQGYYYHZ.js +1180 -0
- package/dist/lib/cubing/chunks/chunk-DQGYYYHZ.js.map +7 -0
- package/dist/lib/cubing/chunks/chunk-FTE3QI5X.js +1074 -0
- package/dist/lib/cubing/chunks/chunk-FTE3QI5X.js.map +7 -0
- package/dist/lib/cubing/chunks/chunk-FZBKZ5ZB.js +265 -0
- package/dist/lib/cubing/chunks/chunk-FZBKZ5ZB.js.map +7 -0
- package/dist/lib/cubing/chunks/chunk-OUM32GEA.js +239 -0
- package/dist/lib/cubing/chunks/chunk-OUM32GEA.js.map +7 -0
- package/dist/lib/cubing/chunks/chunk-SGJ5WPE4.js +1074 -0
- package/dist/lib/cubing/chunks/chunk-SGJ5WPE4.js.map +7 -0
- package/dist/lib/cubing/chunks/chunk-TAVR35KU.js +265 -0
- package/dist/lib/cubing/chunks/chunk-TAVR35KU.js.map +7 -0
- package/dist/lib/cubing/chunks/chunk-VRTKWZPL.js +10084 -0
- package/dist/lib/cubing/chunks/chunk-VRTKWZPL.js.map +7 -0
- package/dist/lib/cubing/chunks/chunk-VSMFYTG6.js +10086 -0
- package/dist/lib/cubing/chunks/chunk-VSMFYTG6.js.map +7 -0
- package/dist/lib/cubing/chunks/inside-IHWQVDVU.js +564 -0
- package/dist/lib/cubing/chunks/inside-IHWQVDVU.js.map +7 -0
- package/dist/lib/cubing/chunks/inside-L2JI2BEY.js +564 -0
- package/dist/lib/cubing/chunks/inside-L2JI2BEY.js.map +7 -0
- package/dist/lib/cubing/chunks/search-dynamic-sgs-side-events-MXHP7O4R.js +1890 -0
- package/dist/lib/cubing/chunks/search-dynamic-sgs-side-events-MXHP7O4R.js.map +7 -0
- package/dist/lib/cubing/chunks/search-dynamic-sgs-side-events-XFECDWOF.js +1890 -0
- package/dist/lib/cubing/chunks/search-dynamic-sgs-side-events-XFECDWOF.js.map +7 -0
- package/dist/lib/cubing/chunks/search-dynamic-sgs-unofficial-CM33KT7L.js +1267 -0
- package/dist/lib/cubing/chunks/search-dynamic-sgs-unofficial-CM33KT7L.js.map +7 -0
- package/dist/lib/cubing/chunks/search-dynamic-sgs-unofficial-Q4LLHL2O.js +1267 -0
- package/dist/lib/cubing/chunks/search-dynamic-sgs-unofficial-Q4LLHL2O.js.map +7 -0
- package/dist/lib/cubing/chunks/search-dynamic-solve-4x4x4-COSEVJBV.js +2922 -0
- package/dist/lib/cubing/chunks/search-dynamic-solve-4x4x4-COSEVJBV.js.map +7 -0
- package/dist/lib/cubing/chunks/search-dynamic-solve-4x4x4-NANDMURR.js +2922 -0
- package/dist/lib/cubing/chunks/search-dynamic-solve-4x4x4-NANDMURR.js.map +7 -0
- package/dist/lib/cubing/chunks/twisty-dynamic-3d-5NZRNZ7C.js +1881 -0
- package/dist/lib/cubing/chunks/twisty-dynamic-3d-5NZRNZ7C.js.map +7 -0
- package/dist/lib/cubing/chunks/twisty-dynamic-3d-VGZIQ64W.js +1927 -0
- package/dist/lib/cubing/chunks/twisty-dynamic-3d-VGZIQ64W.js.map +7 -0
- package/dist/lib/cubing/chunks/twisty-dynamic-3d-XLUOPCLN.js +1881 -0
- package/dist/lib/cubing/chunks/twisty-dynamic-3d-XLUOPCLN.js.map +7 -0
- package/dist/lib/cubing/{events-IfSwQLYm.d.ts → events-CewDA1aS.d.ts} +1 -1
- package/dist/lib/cubing/{index-btIxbuNp.d.ts → index-DabjED-w.d.ts} +1 -1
- package/dist/lib/cubing/kpuzzle/index.d.ts +1 -1
- package/dist/lib/cubing/notation/index.d.ts +1 -1
- package/dist/lib/cubing/protocol/index.d.ts +1 -1
- package/dist/lib/cubing/puzzle-geometry/index.d.ts +2 -2
- package/dist/lib/cubing/puzzles/index.d.ts +1 -1
- package/dist/lib/cubing/scramble/index.d.ts +2 -2
- package/dist/lib/cubing/search/index.d.ts +3 -3
- package/dist/lib/cubing/stream/index.d.ts +3 -3
- package/dist/lib/cubing/twisty/index.d.ts +2 -2
- package/dist/lib/cubing/twisty/index.js +37 -4
- package/dist/lib/cubing/twisty/index.js.map +3 -3
- package/package.json +1 -1
- /package/dist/bin/chunks/{chunk-52ODPET6.js.map → chunk-OI3YIXMQ.js.map} +0 -0
|
@@ -0,0 +1,1180 @@
|
|
|
1
|
+
import {
|
|
2
|
+
from
|
|
3
|
+
} from "./chunk-FUHYAW74.js";
|
|
4
|
+
|
|
5
|
+
// src/cubing/twisty/debug.ts
|
|
6
|
+
var twistyDebugGlobals = {
|
|
7
|
+
shareAllNewRenderers: "auto",
|
|
8
|
+
showRenderStats: false
|
|
9
|
+
};
|
|
10
|
+
function setTwistyDebug(options) {
|
|
11
|
+
for (const [key, value] of Object.entries(options)) {
|
|
12
|
+
if (key in twistyDebugGlobals) {
|
|
13
|
+
twistyDebugGlobals[key] = value;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/cubing/twisty/model/PromiseFreshener.ts
|
|
19
|
+
var StaleDropper = class {
|
|
20
|
+
#latestAssignedIdx = 0;
|
|
21
|
+
#latestResolvedIdx = 0;
|
|
22
|
+
queue(p) {
|
|
23
|
+
return new Promise(async (resolve, reject) => {
|
|
24
|
+
try {
|
|
25
|
+
const idx = ++this.#latestAssignedIdx;
|
|
26
|
+
const result = await p;
|
|
27
|
+
if (idx > this.#latestResolvedIdx) {
|
|
28
|
+
this.#latestResolvedIdx = idx;
|
|
29
|
+
resolve(result);
|
|
30
|
+
}
|
|
31
|
+
} catch (e) {
|
|
32
|
+
reject(e);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// src/cubing/twisty/model/props/TwistyProp.ts
|
|
39
|
+
var globalSourceGeneration = 0;
|
|
40
|
+
var TwistyPropParent = class {
|
|
41
|
+
// Don't overwrite this. Overwrite `canReuseValue` instead.
|
|
42
|
+
canReuse(v1, v2) {
|
|
43
|
+
return v1 === v2 || this.canReuseValue(v1, v2);
|
|
44
|
+
}
|
|
45
|
+
// Overwrite with a cheap semantic comparison when possible.
|
|
46
|
+
// Note that this is not called if `v1 === v2` (in which case the value is automatically reused).
|
|
47
|
+
canReuseValue(_v1, _v2) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
debugGetChildren() {
|
|
51
|
+
return Array.from(this.#children.values());
|
|
52
|
+
}
|
|
53
|
+
// Propagation
|
|
54
|
+
#children = /* @__PURE__ */ new Set();
|
|
55
|
+
addChild(child) {
|
|
56
|
+
this.#children.add(child);
|
|
57
|
+
}
|
|
58
|
+
removeChild(child) {
|
|
59
|
+
this.#children.delete(child);
|
|
60
|
+
}
|
|
61
|
+
lastSourceGeneration = 0;
|
|
62
|
+
// Synchronously marks all descendants as stale. This doesn't actually
|
|
63
|
+
// literally mark as stale, but it updates the last source generation, which
|
|
64
|
+
// is used to tell if a cahced result is stale.
|
|
65
|
+
markStale(sourceEvent) {
|
|
66
|
+
if (sourceEvent.detail.generation !== globalSourceGeneration) {
|
|
67
|
+
throw new Error("A TwistyProp was marked stale too late!");
|
|
68
|
+
}
|
|
69
|
+
if (this.lastSourceGeneration === sourceEvent.detail.generation) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
this.lastSourceGeneration = sourceEvent.detail.generation;
|
|
73
|
+
for (const child of this.#children) {
|
|
74
|
+
child.markStale(sourceEvent);
|
|
75
|
+
}
|
|
76
|
+
this.#scheduleRawDispatch();
|
|
77
|
+
}
|
|
78
|
+
#rawListeners = /* @__PURE__ */ new Set();
|
|
79
|
+
/** @deprecated */
|
|
80
|
+
addRawListener(listener, options) {
|
|
81
|
+
this.#rawListeners.add(listener);
|
|
82
|
+
if (options?.initial) {
|
|
83
|
+
listener();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** @deprecated */
|
|
87
|
+
removeRawListener(listener) {
|
|
88
|
+
this.#rawListeners.delete(listener);
|
|
89
|
+
}
|
|
90
|
+
/** @deprecated */
|
|
91
|
+
#scheduleRawDispatch() {
|
|
92
|
+
if (!this.#rawDispatchPending) {
|
|
93
|
+
this.#rawDispatchPending = true;
|
|
94
|
+
setTimeout(() => this.#dispatchRawListeners(), 0);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
#rawDispatchPending = false;
|
|
98
|
+
#dispatchRawListeners() {
|
|
99
|
+
if (!this.#rawDispatchPending) {
|
|
100
|
+
throw new Error("Invalid dispatch state!");
|
|
101
|
+
}
|
|
102
|
+
for (const listener of this.#rawListeners) {
|
|
103
|
+
listener();
|
|
104
|
+
}
|
|
105
|
+
this.#rawDispatchPending = false;
|
|
106
|
+
}
|
|
107
|
+
#freshListeners = /* @__PURE__ */ new Map();
|
|
108
|
+
// TODO: Pick a better name.
|
|
109
|
+
addFreshListener(listener) {
|
|
110
|
+
const staleDropper = new StaleDropper();
|
|
111
|
+
let lastResult = null;
|
|
112
|
+
const callback = async () => {
|
|
113
|
+
const result = await staleDropper.queue(this.get());
|
|
114
|
+
if (lastResult !== null && this.canReuse(lastResult, result)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
lastResult = result;
|
|
118
|
+
listener(result);
|
|
119
|
+
};
|
|
120
|
+
this.#freshListeners.set(listener, callback);
|
|
121
|
+
this.addRawListener(callback, { initial: true });
|
|
122
|
+
}
|
|
123
|
+
removeFreshListener(listener) {
|
|
124
|
+
this.removeRawListener(this.#freshListeners.get(listener));
|
|
125
|
+
this.#freshListeners.delete(listener);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
var TwistyPropSource = class extends TwistyPropParent {
|
|
129
|
+
#value;
|
|
130
|
+
constructor(initialValue) {
|
|
131
|
+
super();
|
|
132
|
+
this.#value = from(() => this.getDefaultValue());
|
|
133
|
+
if (initialValue) {
|
|
134
|
+
this.#value = this.deriveFromPromiseOrValue(initialValue, this.#value);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
set(input) {
|
|
138
|
+
this.#value = this.deriveFromPromiseOrValue(input, this.#value);
|
|
139
|
+
const sourceEventDetail = {
|
|
140
|
+
sourceProp: this,
|
|
141
|
+
value: this.#value,
|
|
142
|
+
generation: ++globalSourceGeneration
|
|
143
|
+
};
|
|
144
|
+
this.markStale(
|
|
145
|
+
new CustomEvent("stale", {
|
|
146
|
+
detail: sourceEventDetail
|
|
147
|
+
})
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
async get() {
|
|
151
|
+
return this.#value;
|
|
152
|
+
}
|
|
153
|
+
async deriveFromPromiseOrValue(input, oldValuePromise) {
|
|
154
|
+
return this.derive(await input, oldValuePromise);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
var SimpleTwistyPropSource = class extends TwistyPropSource {
|
|
158
|
+
derive(input) {
|
|
159
|
+
return input;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
var NO_VALUE = Symbol("no value");
|
|
163
|
+
var TwistyPropDerived = class extends TwistyPropParent {
|
|
164
|
+
constructor(parents, userVisibleErrorTracker) {
|
|
165
|
+
super();
|
|
166
|
+
this.userVisibleErrorTracker = userVisibleErrorTracker;
|
|
167
|
+
this.#parents = parents;
|
|
168
|
+
for (const parent of Object.values(parents)) {
|
|
169
|
+
parent.addChild(this);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// cachedInputs:
|
|
173
|
+
#parents;
|
|
174
|
+
#cachedLastSuccessfulCalculation = null;
|
|
175
|
+
#cachedLatestGenerationCalculation = null;
|
|
176
|
+
async get() {
|
|
177
|
+
const generation = this.lastSourceGeneration;
|
|
178
|
+
if (this.#cachedLatestGenerationCalculation?.generation === generation) {
|
|
179
|
+
return this.#cachedLatestGenerationCalculation.output;
|
|
180
|
+
}
|
|
181
|
+
const latestGenerationCalculation = {
|
|
182
|
+
generation,
|
|
183
|
+
output: this.#cacheDerive(
|
|
184
|
+
this.#getParents(),
|
|
185
|
+
generation,
|
|
186
|
+
this.#cachedLastSuccessfulCalculation
|
|
187
|
+
)
|
|
188
|
+
};
|
|
189
|
+
this.#cachedLatestGenerationCalculation = latestGenerationCalculation;
|
|
190
|
+
this.userVisibleErrorTracker?.reset();
|
|
191
|
+
return latestGenerationCalculation.output;
|
|
192
|
+
}
|
|
193
|
+
async #getParents() {
|
|
194
|
+
const inputValuePromises = {};
|
|
195
|
+
for (const [key, parent] of Object.entries(this.#parents)) {
|
|
196
|
+
inputValuePromises[key] = parent.get();
|
|
197
|
+
}
|
|
198
|
+
const inputs = {};
|
|
199
|
+
for (const key in this.#parents) {
|
|
200
|
+
inputs[key] = await inputValuePromises[key];
|
|
201
|
+
}
|
|
202
|
+
return inputs;
|
|
203
|
+
}
|
|
204
|
+
async #cacheDerive(inputsPromise, generation, cachedLatestGenerationCalculation = null) {
|
|
205
|
+
const inputs = await inputsPromise;
|
|
206
|
+
const cache = (output) => {
|
|
207
|
+
this.#cachedLastSuccessfulCalculation = {
|
|
208
|
+
inputs,
|
|
209
|
+
output: Promise.resolve(output),
|
|
210
|
+
generation
|
|
211
|
+
};
|
|
212
|
+
return output;
|
|
213
|
+
};
|
|
214
|
+
if (!cachedLatestGenerationCalculation) {
|
|
215
|
+
return cache(await this.derive(inputs));
|
|
216
|
+
}
|
|
217
|
+
const cachedInputs = cachedLatestGenerationCalculation.inputs;
|
|
218
|
+
for (const key in this.#parents) {
|
|
219
|
+
const parent = this.#parents[key];
|
|
220
|
+
if (!parent.canReuse(inputs[key], cachedInputs[key])) {
|
|
221
|
+
return cache(await this.derive(inputs));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return cachedLatestGenerationCalculation.output;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
var FreshListenerManager = class {
|
|
228
|
+
#disconnectionFunctions = [];
|
|
229
|
+
addListener(prop, listener) {
|
|
230
|
+
let disconnected = false;
|
|
231
|
+
const wrappedListener = (value) => {
|
|
232
|
+
if (disconnected) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
listener(value);
|
|
236
|
+
};
|
|
237
|
+
prop.addFreshListener(wrappedListener);
|
|
238
|
+
this.#disconnectionFunctions.push(() => {
|
|
239
|
+
prop.removeFreshListener(wrappedListener);
|
|
240
|
+
disconnected = true;
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
// TODO: Figure out the signature to let us do overloads
|
|
244
|
+
/** @deprecated */
|
|
245
|
+
addMultiListener3(props, listener) {
|
|
246
|
+
this.addMultiListener(props, listener);
|
|
247
|
+
}
|
|
248
|
+
addMultiListener(props, listener) {
|
|
249
|
+
let disconnected = false;
|
|
250
|
+
let initialIgnoresLeft = props.length - 1;
|
|
251
|
+
const wrappedListener = async (_) => {
|
|
252
|
+
if (initialIgnoresLeft > 0) {
|
|
253
|
+
initialIgnoresLeft--;
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (disconnected) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const promises = props.map(
|
|
260
|
+
(prop) => prop.get()
|
|
261
|
+
);
|
|
262
|
+
const values = await Promise.all(promises);
|
|
263
|
+
listener(values);
|
|
264
|
+
};
|
|
265
|
+
for (const prop of props) {
|
|
266
|
+
prop.addFreshListener(wrappedListener);
|
|
267
|
+
}
|
|
268
|
+
this.#disconnectionFunctions.push(() => {
|
|
269
|
+
for (const prop of props) {
|
|
270
|
+
prop.removeFreshListener(wrappedListener);
|
|
271
|
+
}
|
|
272
|
+
disconnected = true;
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
disconnect() {
|
|
276
|
+
for (const disconnectionFunction of this.#disconnectionFunctions) {
|
|
277
|
+
disconnectionFunction();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// src/cubing/twisty/views/node-custom-element-shims.ts
|
|
283
|
+
var HTMLElementStub = class {
|
|
284
|
+
};
|
|
285
|
+
var HTMLElementShim;
|
|
286
|
+
if (globalThis.HTMLElement) {
|
|
287
|
+
HTMLElementShim = globalThis.HTMLElement;
|
|
288
|
+
} else {
|
|
289
|
+
HTMLElementShim = HTMLElementStub;
|
|
290
|
+
}
|
|
291
|
+
var CustomElementsStub = class {
|
|
292
|
+
define() {
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
var customElementsShim;
|
|
296
|
+
if (globalThis.customElements) {
|
|
297
|
+
customElementsShim = globalThis.customElements;
|
|
298
|
+
} else {
|
|
299
|
+
customElementsShim = new CustomElementsStub();
|
|
300
|
+
}
|
|
301
|
+
var cssStyleSheetShim;
|
|
302
|
+
var CSSStyleSheetStub = class {
|
|
303
|
+
replaceSync() {
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
if (globalThis.CSSStyleSheet) {
|
|
307
|
+
cssStyleSheetShim = globalThis.CSSStyleSheet;
|
|
308
|
+
} else {
|
|
309
|
+
cssStyleSheetShim = CSSStyleSheetStub;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// src/cubing/twisty/views/ManagedCustomElement.ts
|
|
313
|
+
var ManagedCustomElement = class extends HTMLElementShim {
|
|
314
|
+
shadow;
|
|
315
|
+
// TODO: hide this
|
|
316
|
+
contentWrapper;
|
|
317
|
+
// TODO: can we get rid of this wrapper?
|
|
318
|
+
constructor(options) {
|
|
319
|
+
super();
|
|
320
|
+
this.shadow = this.attachShadow({ mode: options?.mode ?? "closed" });
|
|
321
|
+
this.contentWrapper = document.createElement("div");
|
|
322
|
+
this.contentWrapper.classList.add("wrapper");
|
|
323
|
+
this.shadow.appendChild(this.contentWrapper);
|
|
324
|
+
}
|
|
325
|
+
// Add the source, if not already added.
|
|
326
|
+
// Returns the existing if it's already on the element.
|
|
327
|
+
addCSS(cssSource) {
|
|
328
|
+
this.shadow.adoptedStyleSheets.push(cssSource);
|
|
329
|
+
}
|
|
330
|
+
removeCSS(cssSource) {
|
|
331
|
+
const cssIndex = this.shadow.adoptedStyleSheets.indexOf(cssSource);
|
|
332
|
+
if (typeof cssIndex !== "undefined") {
|
|
333
|
+
this.shadow.adoptedStyleSheets.splice(cssIndex, cssIndex + 1);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
addElement(element) {
|
|
337
|
+
return this.contentWrapper.appendChild(element);
|
|
338
|
+
}
|
|
339
|
+
prependElement(element) {
|
|
340
|
+
this.contentWrapper.prepend(element);
|
|
341
|
+
}
|
|
342
|
+
removeElement(element) {
|
|
343
|
+
return this.contentWrapper.removeChild(element);
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
customElementsShim.define(
|
|
347
|
+
"twisty-managed-custom-element",
|
|
348
|
+
ManagedCustomElement
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
// src/cubing/twisty/controllers/RenderScheduler.ts
|
|
352
|
+
var RenderScheduler = class {
|
|
353
|
+
constructor(callback) {
|
|
354
|
+
this.callback = callback;
|
|
355
|
+
}
|
|
356
|
+
animFrameID = null;
|
|
357
|
+
animFrame = this.animFrameWrapper.bind(this);
|
|
358
|
+
requestIsPending() {
|
|
359
|
+
return !!this.animFrameID;
|
|
360
|
+
}
|
|
361
|
+
requestAnimFrame() {
|
|
362
|
+
if (!this.animFrameID) {
|
|
363
|
+
this.animFrameID = requestAnimationFrame(this.animFrame);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
cancelAnimFrame() {
|
|
367
|
+
if (this.animFrameID) {
|
|
368
|
+
cancelAnimationFrame(this.animFrameID);
|
|
369
|
+
this.animFrameID = 0;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
animFrameWrapper(timestamp) {
|
|
373
|
+
this.animFrameID = 0;
|
|
374
|
+
this.callback(timestamp);
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
// src/cubing/twisty/model/props/puzzle/display/HintFaceletProp.ts
|
|
379
|
+
var hintFaceletStyles = {
|
|
380
|
+
floating: true,
|
|
381
|
+
// default
|
|
382
|
+
none: true
|
|
383
|
+
};
|
|
384
|
+
var HintFaceletProp = class extends SimpleTwistyPropSource {
|
|
385
|
+
getDefaultValue() {
|
|
386
|
+
return "auto";
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
// src/cubing/twisty/views/3D/TAU.ts
|
|
391
|
+
var TAU = Math.PI * 2;
|
|
392
|
+
var DEGREES_PER_RADIAN = 360 / TAU;
|
|
393
|
+
|
|
394
|
+
// src/cubing/vendor/mit/three/examples/jsm/libs/stats.modified.module.ts
|
|
395
|
+
var performance = globalThis.performance;
|
|
396
|
+
var Stats = class {
|
|
397
|
+
mode = 0;
|
|
398
|
+
dom = document.createElement("div");
|
|
399
|
+
constructor() {
|
|
400
|
+
this.dom.style.cssText = "position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";
|
|
401
|
+
this.dom.addEventListener(
|
|
402
|
+
"click",
|
|
403
|
+
(event) => {
|
|
404
|
+
event.preventDefault();
|
|
405
|
+
this.showPanel(++this.mode % this.dom.children.length);
|
|
406
|
+
},
|
|
407
|
+
false
|
|
408
|
+
);
|
|
409
|
+
this.showPanel(0);
|
|
410
|
+
}
|
|
411
|
+
addPanel(panel) {
|
|
412
|
+
this.dom.appendChild(panel.dom);
|
|
413
|
+
return panel;
|
|
414
|
+
}
|
|
415
|
+
showPanel(id) {
|
|
416
|
+
for (let i = 0; i < this.dom.children.length; i++) {
|
|
417
|
+
this.dom.children[i].style.display = i === id ? "block" : "none";
|
|
418
|
+
}
|
|
419
|
+
this.mode = id;
|
|
420
|
+
}
|
|
421
|
+
beginTime = (performance || Date).now();
|
|
422
|
+
prevTime = this.beginTime;
|
|
423
|
+
frames = 0;
|
|
424
|
+
fpsPanel = this.addPanel(new StatsPanel("FPS", "#0ff", "#002"));
|
|
425
|
+
msPanel = this.addPanel(new StatsPanel("MS", "#0f0", "#020"));
|
|
426
|
+
memPanel = performance?.memory ? this.addPanel(new StatsPanel("MB", "#f08", "#201")) : null;
|
|
427
|
+
REVISION = 16;
|
|
428
|
+
begin() {
|
|
429
|
+
this.beginTime = (performance || Date).now();
|
|
430
|
+
}
|
|
431
|
+
end() {
|
|
432
|
+
this.frames++;
|
|
433
|
+
const time = (performance || Date).now();
|
|
434
|
+
this.msPanel.update(time - this.beginTime, 200);
|
|
435
|
+
if (time >= this.prevTime + 1e3) {
|
|
436
|
+
this.fpsPanel.update(this.frames * 1e3 / (time - this.prevTime), 100);
|
|
437
|
+
this.prevTime = time;
|
|
438
|
+
this.frames = 0;
|
|
439
|
+
if (this.memPanel) {
|
|
440
|
+
const memory = performance.memory;
|
|
441
|
+
this.memPanel.update(
|
|
442
|
+
memory.usedJSHeapSize / 1048576,
|
|
443
|
+
memory.jsHeapSizeLimit / 1048576
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return time;
|
|
448
|
+
}
|
|
449
|
+
update() {
|
|
450
|
+
this.beginTime = this.end();
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
var PR = Math.round(globalThis?.window?.devicePixelRatio ?? 1);
|
|
454
|
+
var WIDTH = 80 * PR;
|
|
455
|
+
var HEIGHT = 48 * PR;
|
|
456
|
+
var TEXT_X = 3 * PR;
|
|
457
|
+
var TEXT_Y = 2 * PR;
|
|
458
|
+
var GRAPH_X = 3 * PR;
|
|
459
|
+
var GRAPH_Y = 15 * PR;
|
|
460
|
+
var GRAPH_WIDTH = 74 * PR;
|
|
461
|
+
var GRAPH_HEIGHT = 30 * PR;
|
|
462
|
+
var StatsPanel = class {
|
|
463
|
+
constructor(name, fg, bg) {
|
|
464
|
+
this.name = name;
|
|
465
|
+
this.fg = fg;
|
|
466
|
+
this.bg = bg;
|
|
467
|
+
this.dom.width = WIDTH;
|
|
468
|
+
this.dom.height = HEIGHT;
|
|
469
|
+
this.dom.style.cssText = "width:80px;height:48px";
|
|
470
|
+
this.context.font = `bold ${9 * PR}px Helvetica,Arial,sans-serif`;
|
|
471
|
+
this.context.textBaseline = "top";
|
|
472
|
+
this.context.fillStyle = bg;
|
|
473
|
+
this.context.fillRect(0, 0, WIDTH, HEIGHT);
|
|
474
|
+
this.context.fillStyle = fg;
|
|
475
|
+
this.context.fillText(name, TEXT_X, TEXT_Y);
|
|
476
|
+
this.context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);
|
|
477
|
+
this.context.fillStyle = bg;
|
|
478
|
+
this.context.globalAlpha = 0.9;
|
|
479
|
+
this.context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);
|
|
480
|
+
}
|
|
481
|
+
min = Infinity;
|
|
482
|
+
max = 0;
|
|
483
|
+
dom = document.createElement("canvas");
|
|
484
|
+
context = this.dom.getContext("2d");
|
|
485
|
+
update(value, maxValue) {
|
|
486
|
+
this.min = Math.min(this.min, value);
|
|
487
|
+
this.max = Math.max(this.max, value);
|
|
488
|
+
this.context.fillStyle = this.bg;
|
|
489
|
+
this.context.globalAlpha = 1;
|
|
490
|
+
this.context.fillRect(0, 0, WIDTH, GRAPH_Y);
|
|
491
|
+
this.context.fillStyle = this.fg;
|
|
492
|
+
this.context.fillText(
|
|
493
|
+
`${Math.round(value)} ${this.name} (${Math.round(this.min)}-${Math.round(
|
|
494
|
+
this.max
|
|
495
|
+
)})`,
|
|
496
|
+
TEXT_X,
|
|
497
|
+
TEXT_Y
|
|
498
|
+
);
|
|
499
|
+
this.context.drawImage(
|
|
500
|
+
this.dom,
|
|
501
|
+
GRAPH_X + PR,
|
|
502
|
+
GRAPH_Y,
|
|
503
|
+
GRAPH_WIDTH - PR,
|
|
504
|
+
GRAPH_HEIGHT,
|
|
505
|
+
GRAPH_X,
|
|
506
|
+
GRAPH_Y,
|
|
507
|
+
GRAPH_WIDTH - PR,
|
|
508
|
+
GRAPH_HEIGHT
|
|
509
|
+
);
|
|
510
|
+
this.context.fillRect(
|
|
511
|
+
GRAPH_X + GRAPH_WIDTH - PR,
|
|
512
|
+
GRAPH_Y,
|
|
513
|
+
PR,
|
|
514
|
+
GRAPH_HEIGHT
|
|
515
|
+
);
|
|
516
|
+
this.context.fillStyle = this.bg;
|
|
517
|
+
this.context.globalAlpha = 0.9;
|
|
518
|
+
this.context.fillRect(
|
|
519
|
+
GRAPH_X + GRAPH_WIDTH - PR,
|
|
520
|
+
GRAPH_Y,
|
|
521
|
+
PR,
|
|
522
|
+
Math.round((1 - value / maxValue) * GRAPH_HEIGHT)
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
// src/cubing/twisty/heavy-code-imports/3d.ts
|
|
528
|
+
var cachedConstructorProxy = null;
|
|
529
|
+
async function bulk3DCode() {
|
|
530
|
+
return cachedConstructorProxy ??= import("./twisty-dynamic-3d-VGZIQ64W.js");
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/cubing/twisty/views/canvas.ts
|
|
534
|
+
var globalPixelRatioOverride = null;
|
|
535
|
+
function pixelRatio() {
|
|
536
|
+
return globalPixelRatioOverride ?? (devicePixelRatio || 1);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// src/cubing/twisty/views/3D/DragTracker.ts
|
|
540
|
+
var MOVEMENT_EPSILON = 0.1;
|
|
541
|
+
var DragTracker = class extends EventTarget {
|
|
542
|
+
constructor(target) {
|
|
543
|
+
super();
|
|
544
|
+
this.target = target;
|
|
545
|
+
}
|
|
546
|
+
#dragInfoMap = /* @__PURE__ */ new Map();
|
|
547
|
+
// Idempotent
|
|
548
|
+
start() {
|
|
549
|
+
this.addTargetListener("pointerdown", this.onPointerDown.bind(this));
|
|
550
|
+
this.addTargetListener("contextmenu", (e) => {
|
|
551
|
+
e.preventDefault();
|
|
552
|
+
});
|
|
553
|
+
this.addTargetListener(
|
|
554
|
+
"touchmove",
|
|
555
|
+
(e) => e.preventDefault()
|
|
556
|
+
);
|
|
557
|
+
this.addTargetListener("dblclick", (e) => e.preventDefault());
|
|
558
|
+
}
|
|
559
|
+
// Idempotent
|
|
560
|
+
stop() {
|
|
561
|
+
for (const [eventType, listener] of this.#targetListeners.entries()) {
|
|
562
|
+
this.target.removeEventListener(
|
|
563
|
+
eventType,
|
|
564
|
+
listener
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
this.#targetListeners.clear();
|
|
568
|
+
this.#lazyListenersRegistered = false;
|
|
569
|
+
}
|
|
570
|
+
#targetListeners = /* @__PURE__ */ new Map();
|
|
571
|
+
addTargetListener(eventType, listener) {
|
|
572
|
+
if (!this.#targetListeners.has(eventType)) {
|
|
573
|
+
this.target.addEventListener(
|
|
574
|
+
eventType,
|
|
575
|
+
listener
|
|
576
|
+
// TODO
|
|
577
|
+
);
|
|
578
|
+
this.#targetListeners.set(eventType, listener);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
// This allows us to avoid getting a callback every time the pointer moves over the canvas, until we have a down event.
|
|
582
|
+
// TODO: Ideally we'd also support unregistering when we're certain there are no more active touches. But this means we need to properly handle every way a pointer "click" can end, which is tricky across environments (due to e.g. mouse vs. touch vs. stylues, canvas/viewport/window/scroll boundaries, right-click and other ways of losing focus, etc.), so we conservatively leave the listeners on.
|
|
583
|
+
#lazyListenersRegistered = false;
|
|
584
|
+
#registerLazyListeners() {
|
|
585
|
+
if (this.#lazyListenersRegistered) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
this.addTargetListener("pointermove", this.onPointerMove.bind(this));
|
|
589
|
+
this.addTargetListener("pointerup", this.onPointerUp.bind(this));
|
|
590
|
+
this.#lazyListenersRegistered = true;
|
|
591
|
+
}
|
|
592
|
+
#clear(e) {
|
|
593
|
+
this.#dragInfoMap.delete(e.pointerId);
|
|
594
|
+
}
|
|
595
|
+
// `null`: means: ignore this result (no movement, or not
|
|
596
|
+
#trackDrag(e) {
|
|
597
|
+
const existing = this.#dragInfoMap.get(e.pointerId);
|
|
598
|
+
if (!existing) {
|
|
599
|
+
return { movementInfo: null, hasMoved: false };
|
|
600
|
+
}
|
|
601
|
+
let movementInfo;
|
|
602
|
+
if ((e.movementX ?? 0) !== 0 || (e.movementY ?? 0) !== 0) {
|
|
603
|
+
movementInfo = {
|
|
604
|
+
attachedInfo: existing.attachedInfo,
|
|
605
|
+
movementX: e.movementX,
|
|
606
|
+
movementY: e.movementY,
|
|
607
|
+
elapsedMs: e.timeStamp - existing.lastTimeStamp
|
|
608
|
+
};
|
|
609
|
+
} else {
|
|
610
|
+
movementInfo = {
|
|
611
|
+
attachedInfo: existing.attachedInfo,
|
|
612
|
+
movementX: e.clientX - existing.lastClientX,
|
|
613
|
+
movementY: e.clientY - existing.lastClientY,
|
|
614
|
+
elapsedMs: e.timeStamp - existing.lastTimeStamp
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
existing.lastClientX = e.clientX;
|
|
618
|
+
existing.lastClientY = e.clientY;
|
|
619
|
+
existing.lastTimeStamp = e.timeStamp;
|
|
620
|
+
if (Math.abs(movementInfo.movementX) < MOVEMENT_EPSILON && Math.abs(movementInfo.movementY) < MOVEMENT_EPSILON) {
|
|
621
|
+
return { movementInfo: null, hasMoved: existing.hasMoved };
|
|
622
|
+
} else {
|
|
623
|
+
existing.hasMoved = true;
|
|
624
|
+
return { movementInfo, hasMoved: existing.hasMoved };
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
onPointerDown(e) {
|
|
628
|
+
this.#registerLazyListeners();
|
|
629
|
+
const newDragInfo = {
|
|
630
|
+
attachedInfo: {},
|
|
631
|
+
hasMoved: false,
|
|
632
|
+
lastClientX: e.clientX,
|
|
633
|
+
lastClientY: e.clientY,
|
|
634
|
+
lastTimeStamp: e.timeStamp
|
|
635
|
+
};
|
|
636
|
+
this.#dragInfoMap.set(e.pointerId, newDragInfo);
|
|
637
|
+
this.target.setPointerCapture(e.pointerId);
|
|
638
|
+
}
|
|
639
|
+
onPointerMove(e) {
|
|
640
|
+
const movementInfo = this.#trackDrag(e).movementInfo;
|
|
641
|
+
if (movementInfo) {
|
|
642
|
+
e.preventDefault();
|
|
643
|
+
this.dispatchEvent(
|
|
644
|
+
new CustomEvent("move", {
|
|
645
|
+
detail: movementInfo
|
|
646
|
+
})
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
onPointerUp(e) {
|
|
651
|
+
const trackDragResult = this.#trackDrag(e);
|
|
652
|
+
const existing = this.#dragInfoMap.get(e.pointerId);
|
|
653
|
+
this.#clear(e);
|
|
654
|
+
this.target.releasePointerCapture(e.pointerId);
|
|
655
|
+
let event;
|
|
656
|
+
if (trackDragResult.hasMoved) {
|
|
657
|
+
event = new CustomEvent("up", {
|
|
658
|
+
detail: { attachedInfo: existing.attachedInfo }
|
|
659
|
+
});
|
|
660
|
+
} else {
|
|
661
|
+
const { altKey, ctrlKey, metaKey, shiftKey } = e;
|
|
662
|
+
event = new CustomEvent("press", {
|
|
663
|
+
detail: {
|
|
664
|
+
normalizedX: e.offsetX / this.target.offsetWidth * 2 - 1,
|
|
665
|
+
normalizedY: 1 - e.offsetY / this.target.offsetHeight * 2,
|
|
666
|
+
rightClick: !!(e.button & 2),
|
|
667
|
+
keys: {
|
|
668
|
+
altKey,
|
|
669
|
+
ctrlOrMetaKey: ctrlKey || metaKey,
|
|
670
|
+
shiftKey
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
this.dispatchEvent(event);
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
// src/cubing/twisty/views/3D/RendererPool.ts
|
|
680
|
+
var renderers = [];
|
|
681
|
+
async function rawRenderPooled(width, height, scene, camera) {
|
|
682
|
+
if (renderers.length === 0) {
|
|
683
|
+
renderers.push(newRenderer());
|
|
684
|
+
}
|
|
685
|
+
const renderer = await renderers[0];
|
|
686
|
+
renderer.setSize(width, height);
|
|
687
|
+
renderer.render(scene, camera);
|
|
688
|
+
return renderer.domElement;
|
|
689
|
+
}
|
|
690
|
+
async function renderPooled(width, height, canvas, scene, camera) {
|
|
691
|
+
if (width === 0 || height === 0) {
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
if (renderers.length === 0) {
|
|
695
|
+
renderers.push(newRenderer());
|
|
696
|
+
}
|
|
697
|
+
const rendererCanvas = await rawRenderPooled(width, height, scene, camera);
|
|
698
|
+
const context = canvas.getContext("2d");
|
|
699
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
700
|
+
context.drawImage(rendererCanvas, 0, 0);
|
|
701
|
+
}
|
|
702
|
+
var linearSRGBColorSpace = "srgb-linear";
|
|
703
|
+
async function newRenderer() {
|
|
704
|
+
const rendererConstructor = (await bulk3DCode()).ThreeWebGLRenderer;
|
|
705
|
+
const renderer = new rendererConstructor({
|
|
706
|
+
antialias: true,
|
|
707
|
+
alpha: true
|
|
708
|
+
});
|
|
709
|
+
renderer.outputColorSpace = linearSRGBColorSpace;
|
|
710
|
+
renderer.setPixelRatio(pixelRatio());
|
|
711
|
+
return renderer;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// src/cubing/twisty/views/3D/Twisty3DVantage.css.ts
|
|
715
|
+
var twisty3DVantageCSS = new cssStyleSheetShim();
|
|
716
|
+
twisty3DVantageCSS.replaceSync(
|
|
717
|
+
`
|
|
718
|
+
:host {
|
|
719
|
+
width: 384px;
|
|
720
|
+
height: 256px;
|
|
721
|
+
display: grid;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.wrapper {
|
|
725
|
+
width: 100%;
|
|
726
|
+
height: 100%;
|
|
727
|
+
display: grid;
|
|
728
|
+
overflow: hidden;
|
|
729
|
+
place-content: center;
|
|
730
|
+
contain: strict;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.loading {
|
|
734
|
+
width: 4em;
|
|
735
|
+
height: 4em;
|
|
736
|
+
border-radius: 2.5em;
|
|
737
|
+
border: 0.5em solid rgba(0, 0, 0, 0);
|
|
738
|
+
border-top: 0.5em solid rgba(0, 0, 0, 0.7);
|
|
739
|
+
border-right: 0.5em solid rgba(0, 0, 0, 0.7);
|
|
740
|
+
animation: fade-in-delayed 4s, rotate 1s linear infinite;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
@keyframes fade-in-delayed {
|
|
744
|
+
0% { opacity: 0; }
|
|
745
|
+
25% {opacity: 0; }
|
|
746
|
+
100% { opacity: 1; }
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
@keyframes rotate {
|
|
750
|
+
from { transform: rotate(0deg); }
|
|
751
|
+
to { transform: rotate(360deg); }
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/* TODO: This is due to stats hack. Replace with \`canvas\`. */
|
|
755
|
+
.wrapper > canvas {
|
|
756
|
+
max-width: 100%;
|
|
757
|
+
max-height: 100%;
|
|
758
|
+
animation: fade-in 0.25s ease-in;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
@keyframes fade-in {
|
|
762
|
+
from { opacity: 0; }
|
|
763
|
+
to { opacity: 1; }
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
.wrapper.invisible {
|
|
767
|
+
opacity: 0;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
.wrapper.drag-input-enabled > canvas {
|
|
771
|
+
cursor: grab;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.wrapper.drag-input-enabled > canvas:active {
|
|
775
|
+
cursor: grabbing;
|
|
776
|
+
}
|
|
777
|
+
`
|
|
778
|
+
);
|
|
779
|
+
|
|
780
|
+
// src/cubing/twisty/views/3D/TwistyOrbitControls.ts
|
|
781
|
+
var INERTIA_DEFAULT = true;
|
|
782
|
+
var INERTIA_DURATION_MS = 500;
|
|
783
|
+
var INERTIA_TIMEOUT_MS = 50;
|
|
784
|
+
var VERTICAL_MOVEMENT_BASE_SCALE = 0.75;
|
|
785
|
+
function momentumScale(progress) {
|
|
786
|
+
return (Math.exp(1 - progress) - (1 - progress)) / (1 - Math.E) + 1;
|
|
787
|
+
}
|
|
788
|
+
var Inertia = class {
|
|
789
|
+
constructor(startTimestamp, momentumX, momentumY, callback) {
|
|
790
|
+
this.startTimestamp = startTimestamp;
|
|
791
|
+
this.momentumX = momentumX;
|
|
792
|
+
this.momentumY = momentumY;
|
|
793
|
+
this.callback = callback;
|
|
794
|
+
this.scheduler.requestAnimFrame();
|
|
795
|
+
this.lastTimestamp = startTimestamp;
|
|
796
|
+
}
|
|
797
|
+
scheduler = new RenderScheduler(this.render.bind(this));
|
|
798
|
+
lastTimestamp;
|
|
799
|
+
render(now) {
|
|
800
|
+
const progressBefore = (this.lastTimestamp - this.startTimestamp) / INERTIA_DURATION_MS;
|
|
801
|
+
const progressAfter = Math.min(
|
|
802
|
+
1,
|
|
803
|
+
(now - this.startTimestamp) / INERTIA_DURATION_MS
|
|
804
|
+
);
|
|
805
|
+
if (progressBefore === 0 && progressAfter > INERTIA_TIMEOUT_MS / INERTIA_DURATION_MS) {
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
const delta = momentumScale(progressAfter) - momentumScale(progressBefore);
|
|
809
|
+
this.callback(this.momentumX * delta * 1e3, this.momentumY * delta * 1e3);
|
|
810
|
+
if (progressAfter < 1) {
|
|
811
|
+
this.scheduler.requestAnimFrame();
|
|
812
|
+
}
|
|
813
|
+
this.lastTimestamp = now;
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
var TwistyOrbitControls = class {
|
|
817
|
+
constructor(model, mirror, canvas, dragTracker) {
|
|
818
|
+
this.model = model;
|
|
819
|
+
this.mirror = mirror;
|
|
820
|
+
this.canvas = canvas;
|
|
821
|
+
this.dragTracker = dragTracker;
|
|
822
|
+
this.dragTracker.addEventListener(
|
|
823
|
+
"move",
|
|
824
|
+
this.onMove.bind(this)
|
|
825
|
+
// TODO: https://github.com/microsoft/TypeScript/issues/28357
|
|
826
|
+
);
|
|
827
|
+
this.dragTracker.addEventListener(
|
|
828
|
+
"up",
|
|
829
|
+
this.onUp.bind(this)
|
|
830
|
+
// TODO: https://github.com/microsoft/TypeScript/issues/28357
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
/** @deprecated */
|
|
834
|
+
experimentalInertia = INERTIA_DEFAULT;
|
|
835
|
+
onMovementBound = this.onMovement.bind(this);
|
|
836
|
+
experimentalHasBeenMoved = false;
|
|
837
|
+
// f is the fraction of the canvas traversed per ms.
|
|
838
|
+
temperMovement(f) {
|
|
839
|
+
return Math.sign(f) * Math.log(Math.abs(f * 10) + 1) / 6;
|
|
840
|
+
}
|
|
841
|
+
onMove(e) {
|
|
842
|
+
e.detail.attachedInfo ??= {};
|
|
843
|
+
const { temperedX, temperedY } = this.onMovement(
|
|
844
|
+
e.detail.movementX,
|
|
845
|
+
e.detail.movementY
|
|
846
|
+
);
|
|
847
|
+
const attachedInfo = e.detail.attachedInfo;
|
|
848
|
+
attachedInfo.lastTemperedX = temperedX * 10;
|
|
849
|
+
attachedInfo.lastTemperedY = temperedY * 10;
|
|
850
|
+
attachedInfo.timestamp = e.timeStamp;
|
|
851
|
+
}
|
|
852
|
+
onMovement(movementX, movementY) {
|
|
853
|
+
const scale = this.mirror ? -1 : 1;
|
|
854
|
+
const minDim = Math.min(this.canvas.offsetWidth, this.canvas.offsetHeight);
|
|
855
|
+
const temperedX = this.temperMovement(movementX / minDim);
|
|
856
|
+
const temperedY = this.temperMovement(
|
|
857
|
+
movementY / minDim * VERTICAL_MOVEMENT_BASE_SCALE
|
|
858
|
+
);
|
|
859
|
+
this.model.twistySceneModel.orbitCoordinatesRequest.set(
|
|
860
|
+
(async () => {
|
|
861
|
+
const prevCoords = await this.model.twistySceneModel.orbitCoordinates.get();
|
|
862
|
+
const newCoords = {
|
|
863
|
+
latitude: prevCoords.latitude + 2 * temperedY * DEGREES_PER_RADIAN * scale,
|
|
864
|
+
longitude: prevCoords.longitude - 2 * temperedX * DEGREES_PER_RADIAN
|
|
865
|
+
};
|
|
866
|
+
return newCoords;
|
|
867
|
+
})()
|
|
868
|
+
);
|
|
869
|
+
return { temperedX, temperedY };
|
|
870
|
+
}
|
|
871
|
+
onUp(e) {
|
|
872
|
+
e.preventDefault();
|
|
873
|
+
if ("lastTemperedX" in e.detail.attachedInfo && "lastTemperedY" in e.detail.attachedInfo && "timestamp" in e.detail.attachedInfo && e.timeStamp - e.detail.attachedInfo["timestamp"] < 60) {
|
|
874
|
+
new Inertia(
|
|
875
|
+
e.timeStamp,
|
|
876
|
+
// TODO
|
|
877
|
+
e.detail.attachedInfo.lastTemperedX,
|
|
878
|
+
e.detail.attachedInfo.lastTemperedY,
|
|
879
|
+
this.onMovementBound
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
// src/cubing/twisty/views/3D/Twisty3DVantage.ts
|
|
886
|
+
async function setCameraFromOrbitCoordinates(camera, orbitCoordinates, backView = false) {
|
|
887
|
+
const spherical = new (await bulk3DCode()).ThreeSpherical(
|
|
888
|
+
orbitCoordinates.distance,
|
|
889
|
+
(90 - (backView ? -1 : 1) * orbitCoordinates.latitude) / DEGREES_PER_RADIAN,
|
|
890
|
+
((backView ? 180 : 0) + orbitCoordinates.longitude) / DEGREES_PER_RADIAN
|
|
891
|
+
);
|
|
892
|
+
spherical.makeSafe();
|
|
893
|
+
camera.position.setFromSpherical(spherical);
|
|
894
|
+
camera.lookAt(0, 0, 0);
|
|
895
|
+
}
|
|
896
|
+
var dedicatedRenderersSoFar = 0;
|
|
897
|
+
var DEFAULT_MAX_DEDICATED_RENDERERS = 2;
|
|
898
|
+
var sharingRenderers = false;
|
|
899
|
+
function shareRenderer() {
|
|
900
|
+
if (twistyDebugGlobals.shareAllNewRenderers !== "auto") {
|
|
901
|
+
if (!twistyDebugGlobals.shareAllNewRenderers) {
|
|
902
|
+
dedicatedRenderersSoFar++;
|
|
903
|
+
}
|
|
904
|
+
return twistyDebugGlobals.shareAllNewRenderers !== "never";
|
|
905
|
+
}
|
|
906
|
+
if (dedicatedRenderersSoFar < DEFAULT_MAX_DEDICATED_RENDERERS) {
|
|
907
|
+
dedicatedRenderersSoFar++;
|
|
908
|
+
return false;
|
|
909
|
+
} else {
|
|
910
|
+
sharingRenderers = true;
|
|
911
|
+
return true;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
function haveStartedSharingRenderers() {
|
|
915
|
+
return sharingRenderers;
|
|
916
|
+
}
|
|
917
|
+
var Twisty3DVantage = class extends ManagedCustomElement {
|
|
918
|
+
constructor(model, scene, options) {
|
|
919
|
+
super();
|
|
920
|
+
this.model = model;
|
|
921
|
+
this.options = options;
|
|
922
|
+
this.scene = scene ?? null;
|
|
923
|
+
this.loadingElement = this.addElement(document.createElement("div"));
|
|
924
|
+
this.loadingElement.classList.add("loading");
|
|
925
|
+
if (twistyDebugGlobals.showRenderStats) {
|
|
926
|
+
this.stats = new Stats();
|
|
927
|
+
this.stats.dom.style.position = "absolute";
|
|
928
|
+
this.contentWrapper.appendChild(this.stats.dom);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
scene = null;
|
|
932
|
+
stats = null;
|
|
933
|
+
rendererIsShared = shareRenderer();
|
|
934
|
+
loadingElement = null;
|
|
935
|
+
async connectedCallback() {
|
|
936
|
+
this.addCSS(twisty3DVantageCSS);
|
|
937
|
+
this.addElement((await this.canvasInfo()).canvas);
|
|
938
|
+
void this.#onResize();
|
|
939
|
+
const observer = new ResizeObserver(this.#onResize.bind(this));
|
|
940
|
+
observer.observe(this.contentWrapper);
|
|
941
|
+
void this.orbitControls();
|
|
942
|
+
void this.#setupBasicPresses();
|
|
943
|
+
this.scheduleRender();
|
|
944
|
+
}
|
|
945
|
+
async #setupBasicPresses() {
|
|
946
|
+
const dragTracker = await this.#dragTracker();
|
|
947
|
+
dragTracker.addEventListener(
|
|
948
|
+
"press",
|
|
949
|
+
(async (e) => {
|
|
950
|
+
const movePressInput = await this.model.twistySceneModel.movePressInput.get();
|
|
951
|
+
if (movePressInput !== "basic") {
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
this.dispatchEvent(
|
|
955
|
+
new CustomEvent("press", {
|
|
956
|
+
detail: {
|
|
957
|
+
pressInfo: e.detail,
|
|
958
|
+
cameraPromise: this.camera()
|
|
959
|
+
}
|
|
960
|
+
})
|
|
961
|
+
);
|
|
962
|
+
})
|
|
963
|
+
// TODO
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
#onResizeStaleDropper = new StaleDropper();
|
|
967
|
+
async clearCanvas() {
|
|
968
|
+
if (this.rendererIsShared) {
|
|
969
|
+
const canvasInfo = await this.canvasInfo();
|
|
970
|
+
canvasInfo.context.clearRect(
|
|
971
|
+
0,
|
|
972
|
+
0,
|
|
973
|
+
canvasInfo.canvas.width,
|
|
974
|
+
canvasInfo.canvas.height
|
|
975
|
+
);
|
|
976
|
+
} else {
|
|
977
|
+
const renderer = await this.renderer();
|
|
978
|
+
const context = renderer.getContext();
|
|
979
|
+
context.clear(context.COLOR_BUFFER_BIT);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
// TODO: Why doesn't this work for the top-right back view height?
|
|
983
|
+
#width = 0;
|
|
984
|
+
#height = 0;
|
|
985
|
+
async #onResize() {
|
|
986
|
+
const camera = await this.#onResizeStaleDropper.queue(this.camera());
|
|
987
|
+
const w = this.contentWrapper.clientWidth;
|
|
988
|
+
const h = this.contentWrapper.clientHeight;
|
|
989
|
+
this.#width = w;
|
|
990
|
+
this.#height = h;
|
|
991
|
+
const off = 0;
|
|
992
|
+
let yoff = 0;
|
|
993
|
+
let excess = 0;
|
|
994
|
+
if (h > w) {
|
|
995
|
+
excess = h - w;
|
|
996
|
+
yoff = -Math.floor(0.5 * excess);
|
|
997
|
+
}
|
|
998
|
+
camera.aspect = w / h;
|
|
999
|
+
camera.setViewOffset(w, h - excess, off, yoff, w, h);
|
|
1000
|
+
camera.updateProjectionMatrix();
|
|
1001
|
+
void this.clearCanvas();
|
|
1002
|
+
if (this.rendererIsShared) {
|
|
1003
|
+
const canvasInfo = await this.canvasInfo();
|
|
1004
|
+
canvasInfo.canvas.width = w * pixelRatio();
|
|
1005
|
+
canvasInfo.canvas.height = h * pixelRatio();
|
|
1006
|
+
canvasInfo.canvas.style.width = `${w.toString()}px`;
|
|
1007
|
+
canvasInfo.canvas.style.height = `${h.toString()}px`;
|
|
1008
|
+
} else {
|
|
1009
|
+
const renderer = await this.renderer();
|
|
1010
|
+
renderer.setSize(w, h, true);
|
|
1011
|
+
}
|
|
1012
|
+
this.scheduleRender();
|
|
1013
|
+
}
|
|
1014
|
+
#cachedRenderer = null;
|
|
1015
|
+
async renderer() {
|
|
1016
|
+
if (this.rendererIsShared) {
|
|
1017
|
+
throw new Error("renderer expected to be shared.");
|
|
1018
|
+
}
|
|
1019
|
+
return this.#cachedRenderer ??= newRenderer();
|
|
1020
|
+
}
|
|
1021
|
+
#cachedCanvas = null;
|
|
1022
|
+
async canvasInfo() {
|
|
1023
|
+
return this.#cachedCanvas ??= (async () => {
|
|
1024
|
+
let canvas;
|
|
1025
|
+
if (this.rendererIsShared) {
|
|
1026
|
+
canvas = this.addElement(document.createElement("canvas"));
|
|
1027
|
+
} else {
|
|
1028
|
+
const renderer = await this.renderer();
|
|
1029
|
+
canvas = this.addElement(renderer.domElement);
|
|
1030
|
+
}
|
|
1031
|
+
this.loadingElement?.remove();
|
|
1032
|
+
const context = canvas.getContext("2d");
|
|
1033
|
+
return { canvas, context };
|
|
1034
|
+
})();
|
|
1035
|
+
}
|
|
1036
|
+
#cachedDragTracker = null;
|
|
1037
|
+
async #dragTracker() {
|
|
1038
|
+
return this.#cachedDragTracker ??= (async () => {
|
|
1039
|
+
const dragTracker = new DragTracker((await this.canvasInfo()).canvas);
|
|
1040
|
+
this.model?.twistySceneModel.dragInput.addFreshListener(
|
|
1041
|
+
(dragInputMode) => {
|
|
1042
|
+
let dragInputEnabled = false;
|
|
1043
|
+
switch (dragInputMode) {
|
|
1044
|
+
case "auto": {
|
|
1045
|
+
dragTracker.start();
|
|
1046
|
+
dragInputEnabled = true;
|
|
1047
|
+
break;
|
|
1048
|
+
}
|
|
1049
|
+
case "none": {
|
|
1050
|
+
dragTracker.stop();
|
|
1051
|
+
break;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
this.contentWrapper.classList.toggle(
|
|
1055
|
+
"drag-input-enabled",
|
|
1056
|
+
dragInputEnabled
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1059
|
+
);
|
|
1060
|
+
return dragTracker;
|
|
1061
|
+
})();
|
|
1062
|
+
}
|
|
1063
|
+
#cachedCamera = null;
|
|
1064
|
+
async camera() {
|
|
1065
|
+
return this.#cachedCamera ??= (async () => {
|
|
1066
|
+
const camera = new (await bulk3DCode()).ThreePerspectiveCamera(
|
|
1067
|
+
20,
|
|
1068
|
+
1,
|
|
1069
|
+
// We rely on the resize logic to handle this.
|
|
1070
|
+
0.1,
|
|
1071
|
+
20
|
|
1072
|
+
);
|
|
1073
|
+
camera.position.copy(
|
|
1074
|
+
new (await bulk3DCode()).ThreeVector3(2, 4, 4).multiplyScalar(
|
|
1075
|
+
this.options?.backView ? -1 : 1
|
|
1076
|
+
)
|
|
1077
|
+
);
|
|
1078
|
+
camera.lookAt(0, 0, 0);
|
|
1079
|
+
return camera;
|
|
1080
|
+
})();
|
|
1081
|
+
}
|
|
1082
|
+
#cachedOrbitControls = null;
|
|
1083
|
+
async orbitControls() {
|
|
1084
|
+
return this.#cachedOrbitControls ??= (async () => {
|
|
1085
|
+
const orbitControls = new TwistyOrbitControls(
|
|
1086
|
+
this.model,
|
|
1087
|
+
!!this.options?.backView,
|
|
1088
|
+
(await this.canvasInfo()).canvas,
|
|
1089
|
+
await this.#dragTracker()
|
|
1090
|
+
);
|
|
1091
|
+
if (this.model) {
|
|
1092
|
+
this.addListener(
|
|
1093
|
+
this.model.twistySceneModel.orbitCoordinates,
|
|
1094
|
+
async (orbitCoordinates) => {
|
|
1095
|
+
const camera = await this.camera();
|
|
1096
|
+
void setCameraFromOrbitCoordinates(
|
|
1097
|
+
camera,
|
|
1098
|
+
orbitCoordinates,
|
|
1099
|
+
this.options?.backView
|
|
1100
|
+
);
|
|
1101
|
+
this.scheduleRender();
|
|
1102
|
+
}
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1105
|
+
return orbitControls;
|
|
1106
|
+
})();
|
|
1107
|
+
}
|
|
1108
|
+
addListener(prop, listener) {
|
|
1109
|
+
prop.addFreshListener(listener);
|
|
1110
|
+
this.#disconnectionFunctions.push(() => {
|
|
1111
|
+
prop.removeFreshListener(listener);
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
#disconnectionFunctions = [];
|
|
1115
|
+
disconnect() {
|
|
1116
|
+
for (const fn of this.#disconnectionFunctions) {
|
|
1117
|
+
fn();
|
|
1118
|
+
}
|
|
1119
|
+
this.#disconnectionFunctions = [];
|
|
1120
|
+
}
|
|
1121
|
+
#experimentalNextRenderFinishedCallback = null;
|
|
1122
|
+
experimentalNextRenderFinishedCallback(callback) {
|
|
1123
|
+
this.#experimentalNextRenderFinishedCallback = callback;
|
|
1124
|
+
}
|
|
1125
|
+
async render() {
|
|
1126
|
+
if (!this.scene) {
|
|
1127
|
+
throw new Error("Attempted to render without a scene");
|
|
1128
|
+
}
|
|
1129
|
+
this.stats?.begin();
|
|
1130
|
+
const [scene, camera, canvas] = await Promise.all([
|
|
1131
|
+
this.scene.scene(),
|
|
1132
|
+
this.camera(),
|
|
1133
|
+
this.canvasInfo()
|
|
1134
|
+
]);
|
|
1135
|
+
if (this.rendererIsShared) {
|
|
1136
|
+
await renderPooled(
|
|
1137
|
+
this.#width,
|
|
1138
|
+
this.#height,
|
|
1139
|
+
canvas.canvas,
|
|
1140
|
+
scene,
|
|
1141
|
+
camera
|
|
1142
|
+
);
|
|
1143
|
+
} else {
|
|
1144
|
+
(await this.renderer()).render(scene, camera);
|
|
1145
|
+
}
|
|
1146
|
+
this.stats?.end();
|
|
1147
|
+
this.#experimentalNextRenderFinishedCallback?.();
|
|
1148
|
+
this.#experimentalNextRenderFinishedCallback = null;
|
|
1149
|
+
}
|
|
1150
|
+
#scheduler = new RenderScheduler(this.render.bind(this));
|
|
1151
|
+
scheduleRender() {
|
|
1152
|
+
this.#scheduler.requestAnimFrame();
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
customElementsShim.define("twisty-3d-vantage", Twisty3DVantage);
|
|
1156
|
+
|
|
1157
|
+
export {
|
|
1158
|
+
setTwistyDebug,
|
|
1159
|
+
StaleDropper,
|
|
1160
|
+
TwistyPropSource,
|
|
1161
|
+
SimpleTwistyPropSource,
|
|
1162
|
+
NO_VALUE,
|
|
1163
|
+
TwistyPropDerived,
|
|
1164
|
+
FreshListenerManager,
|
|
1165
|
+
HTMLElementShim,
|
|
1166
|
+
customElementsShim,
|
|
1167
|
+
cssStyleSheetShim,
|
|
1168
|
+
ManagedCustomElement,
|
|
1169
|
+
RenderScheduler,
|
|
1170
|
+
hintFaceletStyles,
|
|
1171
|
+
HintFaceletProp,
|
|
1172
|
+
TAU,
|
|
1173
|
+
DEGREES_PER_RADIAN,
|
|
1174
|
+
rawRenderPooled,
|
|
1175
|
+
setCameraFromOrbitCoordinates,
|
|
1176
|
+
haveStartedSharingRenderers,
|
|
1177
|
+
Twisty3DVantage,
|
|
1178
|
+
bulk3DCode
|
|
1179
|
+
};
|
|
1180
|
+
//# sourceMappingURL=chunk-DQGYYYHZ.js.map
|