cubing 0.61.0 → 0.61.2

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.
Files changed (77) hide show
  1. package/dist/bin/chunks/chunk-BIRBVHTR.js +14 -0
  2. package/dist/bin/chunks/chunk-BIRBVHTR.js.map +7 -0
  3. package/dist/bin/order.js +46 -42
  4. package/dist/bin/order.js.map +2 -2
  5. package/dist/bin/puzzle-geometry-bin.js +379 -257
  6. package/dist/bin/puzzle-geometry-bin.js.map +3 -3
  7. package/dist/bin/scramble.js +124 -102
  8. package/dist/bin/scramble.js.map +3 -3
  9. package/dist/lib/cubing/{KPattern-CU9Suh1T.d.ts → PuzzleLoader-CkghxdIL.d.ts} +186 -179
  10. package/dist/lib/cubing/alg/index.d.ts +2 -2
  11. package/dist/lib/cubing/bluetooth/index.d.ts +3 -3
  12. package/dist/lib/cubing/bluetooth/index.js +4 -4
  13. package/dist/lib/cubing/{bluetooth-puzzle-gTRbIRyj.d.ts → bluetooth-puzzle-c-_IBAdu.d.ts} +1 -1
  14. package/dist/lib/cubing/chunks/{chunk-PVOSBZRD.js → chunk-3PS5LIPR.js} +3 -3
  15. package/dist/lib/cubing/chunks/{chunk-PVOSBZRD.js.map → chunk-3PS5LIPR.js.map} +1 -1
  16. package/dist/lib/cubing/chunks/{chunk-RKTO4CAU.js → chunk-IHFKNNCV.js} +2 -2
  17. package/dist/lib/cubing/chunks/{chunk-BUZPONAW.js → chunk-LCJT5ROJ.js} +2 -2
  18. package/dist/lib/cubing/chunks/{chunk-WIZJQ7QS.js → chunk-MZKROP74.js} +15 -15
  19. package/dist/lib/cubing/chunks/{chunk-RUSWM2KK.js → chunk-QSGI7DXX.js} +5 -5
  20. package/dist/lib/cubing/chunks/{chunk-RUSWM2KK.js.map → chunk-QSGI7DXX.js.map} +1 -1
  21. package/dist/lib/cubing/chunks/{chunk-REBGU5ET.js → chunk-T3SF7NHB.js} +2 -2
  22. package/dist/lib/cubing/chunks/{chunk-PSQEELP4.js → chunk-WAYEJXCG.js} +1 -1
  23. package/dist/lib/cubing/chunks/chunk-WAYEJXCG.js.map +7 -0
  24. package/dist/lib/cubing/chunks/{chunk-ABQAUY7H.js → chunk-WI337PMF.js} +3 -3
  25. package/dist/lib/cubing/chunks/{chunk-OJI4YUWF.js → chunk-ZGT5MZSV.js} +4 -4
  26. package/dist/lib/cubing/chunks/{chunk-NX2Q6B7Y.js → chunk-ZKJKRQKY.js} +2 -2
  27. package/dist/lib/cubing/chunks/{chunk-NX2Q6B7Y.js.map → chunk-ZKJKRQKY.js.map} +2 -2
  28. package/dist/lib/cubing/chunks/{inside-PM6546BQ.js → inside-UAY7NCJR.js} +12 -12
  29. package/dist/lib/cubing/chunks/{puzzles-dynamic-3x3x3-JWIWLLZA.js → puzzles-dynamic-3x3x3-FYXD7SIU.js} +14 -13
  30. package/dist/lib/cubing/chunks/puzzles-dynamic-3x3x3-FYXD7SIU.js.map +7 -0
  31. package/dist/lib/cubing/chunks/{puzzles-dynamic-side-events-BOGUHF4Q.js → puzzles-dynamic-side-events-IMYJ533P.js} +1 -1
  32. package/dist/lib/cubing/chunks/puzzles-dynamic-side-events-IMYJ533P.js.map +7 -0
  33. package/dist/lib/cubing/chunks/{search-dynamic-sgs-side-events-SYC27DSG.js → search-dynamic-sgs-side-events-E5KVBK2Y.js} +4 -4
  34. package/dist/lib/cubing/chunks/{search-dynamic-sgs-unofficial-QGGV4PCJ.js → search-dynamic-sgs-unofficial-IFHNOIEL.js} +4 -4
  35. package/dist/lib/cubing/chunks/{search-dynamic-solve-4x4x4-IE5W637Q.js → search-dynamic-solve-4x4x4-QVAXVZBA.js} +7 -7
  36. package/dist/lib/cubing/chunks/search-worker-entry.js +3 -3
  37. package/dist/lib/cubing/chunks/{twisty-dynamic-3d-LPZQIDD2.js → twisty-dynamic-3d-O6UL3R7C.js} +5 -5
  38. package/dist/lib/cubing/{index-CORXpckt.d.ts → index-B_8W-2zR.d.ts} +1 -1
  39. package/dist/lib/cubing/kpuzzle/index.d.ts +1 -1
  40. package/dist/lib/cubing/kpuzzle/index.js +1 -1
  41. package/dist/lib/cubing/notation/index.d.ts +1 -1
  42. package/dist/lib/cubing/notation/index.js +3 -3
  43. package/dist/lib/cubing/protocol/index.d.ts +1 -1
  44. package/dist/lib/cubing/protocol/index.js +3 -3
  45. package/dist/lib/cubing/puzzle-geometry/index.d.ts +2 -2
  46. package/dist/lib/cubing/puzzle-geometry/index.js +138 -179
  47. package/dist/lib/cubing/puzzle-geometry/index.js.map +3 -3
  48. package/dist/lib/cubing/puzzles/index.d.ts +1 -1
  49. package/dist/lib/cubing/puzzles/index.js +3 -3
  50. package/dist/lib/cubing/scramble/index.d.ts +2 -2
  51. package/dist/lib/cubing/scramble/index.js +6 -6
  52. package/dist/lib/cubing/search/index.d.ts +3 -3
  53. package/dist/lib/cubing/search/index.js +6 -6
  54. package/dist/lib/cubing/stream/index.d.ts +2 -2
  55. package/dist/lib/cubing/twisty/index.d.ts +2 -2
  56. package/dist/lib/cubing/twisty/index.js +26 -5
  57. package/dist/lib/cubing/twisty/index.js.map +2 -2
  58. package/experimental-json-schema/kpuzzle/KPatternData.schema.json +22 -30
  59. package/experimental-json-schema/kpuzzle/KPuzzleDefinition.schema.json +72 -89
  60. package/experimental-json-schema/kpuzzle/KTransformationData.schema.json +17 -26
  61. package/package.json +55 -100
  62. package/dist/bin/chunks/chunk-J53ID3VX.js +0 -26
  63. package/dist/bin/chunks/chunk-J53ID3VX.js.map +0 -7
  64. package/dist/lib/cubing/chunks/chunk-PSQEELP4.js.map +0 -7
  65. package/dist/lib/cubing/chunks/puzzles-dynamic-3x3x3-JWIWLLZA.js.map +0 -7
  66. package/dist/lib/cubing/chunks/puzzles-dynamic-side-events-BOGUHF4Q.js.map +0 -7
  67. /package/dist/lib/cubing/chunks/{chunk-RKTO4CAU.js.map → chunk-IHFKNNCV.js.map} +0 -0
  68. /package/dist/lib/cubing/chunks/{chunk-BUZPONAW.js.map → chunk-LCJT5ROJ.js.map} +0 -0
  69. /package/dist/lib/cubing/chunks/{chunk-WIZJQ7QS.js.map → chunk-MZKROP74.js.map} +0 -0
  70. /package/dist/lib/cubing/chunks/{chunk-REBGU5ET.js.map → chunk-T3SF7NHB.js.map} +0 -0
  71. /package/dist/lib/cubing/chunks/{chunk-ABQAUY7H.js.map → chunk-WI337PMF.js.map} +0 -0
  72. /package/dist/lib/cubing/chunks/{chunk-OJI4YUWF.js.map → chunk-ZGT5MZSV.js.map} +0 -0
  73. /package/dist/lib/cubing/chunks/{inside-PM6546BQ.js.map → inside-UAY7NCJR.js.map} +0 -0
  74. /package/dist/lib/cubing/chunks/{search-dynamic-sgs-side-events-SYC27DSG.js.map → search-dynamic-sgs-side-events-E5KVBK2Y.js.map} +0 -0
  75. /package/dist/lib/cubing/chunks/{search-dynamic-sgs-unofficial-QGGV4PCJ.js.map → search-dynamic-sgs-unofficial-IFHNOIEL.js.map} +0 -0
  76. /package/dist/lib/cubing/chunks/{search-dynamic-solve-4x4x4-IE5W637Q.js.map → search-dynamic-solve-4x4x4-QVAXVZBA.js.map} +0 -0
  77. /package/dist/lib/cubing/chunks/{twisty-dynamic-3d-LPZQIDD2.js.map → twisty-dynamic-3d-O6UL3R7C.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/cubing/twisty/debug.ts", "../../../../src/cubing/twisty/model/PromiseFreshener.ts", "../../../../src/cubing/twisty/model/props/TwistyProp.ts", "../../../../src/cubing/twisty/views/node-custom-element-shims.ts", "../../../../src/cubing/twisty/views/ManagedCustomElement.ts", "../../../../src/cubing/twisty/controllers/RenderScheduler.ts", "../../../../src/cubing/twisty/model/props/puzzle/display/HintFaceletProp.ts", "../../../../src/cubing/twisty/views/3D/TAU.ts", "../../../../src/cubing/vendor/mit/three/examples/jsm/libs/stats.modified.module.ts", "../../../../src/cubing/twisty/heavy-code-imports/3d.ts", "../../../../src/cubing/twisty/views/canvas.ts", "../../../../src/cubing/twisty/views/3D/DragTracker.ts", "../../../../src/cubing/twisty/views/3D/RendererPool.ts", "../../../../src/cubing/twisty/views/3D/Twisty3DVantage.css.ts", "../../../../src/cubing/twisty/views/3D/TwistyOrbitControls.ts", "../../../../src/cubing/twisty/views/3D/Twisty3DVantage.ts"],
4
- "sourcesContent": ["export const twistyDebugGlobals: {\n // WARNING: The current shared renderer implementation has performance issues, especially in Safari.\n // Avoid using for players that are likely to have dimensions approaching 1 megapixel or higher.\n // TODO: use a dedicated renderer while fullscreen?\n // - \"auto\": Default heuristics.\n // - \"always\": Force all new (i.e. constructed in the future) renderers to be shared\n // - \"never\": Force all new (i.e. constructed in the future) renderers to be dedicated\n shareAllNewRenderers: \"auto\" | \"always\" | \"never\";\n showRenderStats: boolean;\n} = {\n shareAllNewRenderers: \"auto\",\n showRenderStats: false,\n};\n\nexport function setTwistyDebug(\n options: Partial<typeof twistyDebugGlobals>,\n): void {\n for (const [key, value] of Object.entries(options)) {\n if (key in twistyDebugGlobals) {\n (twistyDebugGlobals as any)[key] = value;\n }\n }\n}\n", "// TODO: Pick a much better name.\nexport class PromiseFreshener<T> {\n #latestAssignedIdx = 0;\n #latestResolvedIdx = 0;\n\n // TODO: reject instead? Drop?\n async queue(\n p: Promise<T>,\n ): Promise<{ fresh: false } | { fresh: true; result: T }> {\n const idx = ++this.#latestAssignedIdx;\n const result = await p;\n if (idx > this.#latestResolvedIdx) {\n this.#latestResolvedIdx = idx;\n return {\n fresh: true,\n result: result,\n };\n } else {\n return { fresh: false };\n }\n }\n}\n\n// This will silenty drop a queued Promise (i.e. not resolve it) if a\n// newer queued one already resolved first. This is useful for classes that want\n// to know the \"latest\" state of something without jumping back to an older\n// value by accident.\n// TODO: Remove this because it's too easy to misuse?\nexport class StaleDropper<T> {\n #latestAssignedIdx = 0;\n #latestResolvedIdx = 0;\n\n queue(p: Promise<T>): Promise<T> {\n // biome-ignore lint/suspicious/noAsyncPromiseExecutor: This is a very rare case where we *do* want to drop a Promise sometimes.\n return new Promise(async (resolve, reject) => {\n try {\n const idx = ++this.#latestAssignedIdx;\n const result = await p;\n if (idx > this.#latestResolvedIdx) {\n this.#latestResolvedIdx = idx;\n resolve(result);\n }\n } catch (e) {\n reject(e);\n }\n });\n }\n}\n", "import type { Tagged } from \"type-fest\";\nimport { from } from \"../../../vendor/mit/p-lazy/p-lazy\";\nimport { StaleDropper } from \"../PromiseFreshener\";\nimport type { UserVisibleErrorTracker } from \"../UserVisibleErrorTracker\";\n\ntype InputRecord = Record<string, any>;\n\nexport type InputProps<T extends InputRecord> = {\n [s in keyof T]: TwistyPropParent<T[s]>;\n};\n\ntype InputPromises<T extends InputRecord> = {\n [s in keyof T]: Promise<T[s]>;\n};\n\ntype Generation = Tagged<number, \"Generation\">;\n\ninterface SourceEventDetail<OutputType> {\n sourceProp: TwistyPropSource<OutputType, any>;\n value: Promise<OutputType>; // TODO: remove?\n generation: Generation;\n}\n\ntype SourceEvent<T> = CustomEvent<SourceEventDetail<T>>;\n\nexport type PromiseOrValue<T> = T | Promise<T>;\n\n// Values of T must be immutable.\nlet globalSourceGeneration: Generation = 0 as Generation; // This is incremented before being used, so 1 will be the first active value.\nexport abstract class TwistyPropParent<T> {\n public abstract get(): Promise<T>;\n\n // Don't overwrite this. Overwrite `canReuseValue` instead.\n public canReuse(v1: T, v2: T): boolean {\n return v1 === v2 || this.canReuseValue(v1, v2);\n }\n\n // Overwrite with a cheap semantic comparison when possible.\n // Note that this is not called if `v1 === v2` (in which case the value is automatically reused).\n protected canReuseValue(_v1: T, _v2: T): boolean {\n return false;\n }\n\n debugGetChildren(): TwistyPropDerived<any, any>[] {\n return Array.from(this.#children.values());\n }\n\n // Propagation\n\n #children: Set<TwistyPropDerived<any, any>> = new Set();\n protected addChild(child: TwistyPropDerived<any, any>): void {\n this.#children.add(child);\n }\n\n protected removeChild(child: TwistyPropDerived<any, any>): void {\n this.#children.delete(child);\n }\n\n protected lastSourceGeneration: number = 0;\n // Synchronously marks all descendants as stale. This doesn't actually\n // literally mark as stale, but it updates the last source generation, which\n // is used to tell if a cahced result is stale.\n protected markStale(sourceEvent: SourceEvent<any>): void {\n if (sourceEvent.detail.generation !== globalSourceGeneration) {\n // The full stale propagation is synchronous, so there should not be a new one yet.\n throw new Error(\"A TwistyProp was marked stale too late!\");\n }\n if (this.lastSourceGeneration === sourceEvent.detail.generation) {\n // Already propagated.\n return;\n }\n this.lastSourceGeneration = sourceEvent.detail.generation;\n for (const child of this.#children) {\n child.markStale(sourceEvent);\n }\n // We schedule sending out events *after* the (synchronous) propagation has happened, in\n // case one of the listeners updates a source again.\n this.#scheduleRawDispatch();\n }\n\n #rawListeners: Set<() => void> = new Set();\n /** @deprecated */\n addRawListener(listener: () => void, options?: { initial: boolean }): void {\n this.#rawListeners.add(listener);\n if (options?.initial) {\n listener(); // TODO: wrap in a try?\n }\n }\n\n /** @deprecated */\n removeRawListener(listener: () => void): void {\n this.#rawListeners.delete(listener);\n }\n\n /** @deprecated */\n #scheduleRawDispatch(): void {\n if (!this.#rawDispatchPending) {\n this.#rawDispatchPending = true;\n setTimeout(() => this.#dispatchRawListeners(), 0);\n }\n }\n\n #rawDispatchPending: boolean = false;\n #dispatchRawListeners(): void {\n if (!this.#rawDispatchPending) {\n throw new Error(\"Invalid dispatch state!\");\n }\n for (const listener of this.#rawListeners) {\n listener(); // TODO: wrap in a try?\n }\n this.#rawDispatchPending = false;\n }\n\n #freshListeners: Map<(value: T) => void, () => void> = new Map();\n // TODO: Pick a better name.\n public addFreshListener(listener: (value: T) => void): void {\n const staleDropper: StaleDropper<T> = new StaleDropper<T>();\n let lastResult: T | null = null;\n const callback = async () => {\n const result = await staleDropper.queue(this.get());\n if (lastResult !== null && this.canReuse(lastResult, result)) {\n return;\n }\n lastResult = result;\n listener(result);\n };\n this.#freshListeners.set(listener, callback);\n this.addRawListener(callback, { initial: true });\n }\n\n public removeFreshListener(listener: (value: T) => void): void {\n this.removeRawListener(this.#freshListeners.get(listener)!); // TODO: throw a custom error?\n this.#freshListeners.delete(listener);\n }\n}\n\nexport abstract class TwistyPropSource<\n OutputType,\n InputType = OutputType,\n> extends TwistyPropParent<OutputType> {\n #value: Promise<OutputType>;\n\n public abstract getDefaultValue(): PromiseOrValue<OutputType>;\n\n constructor(initialValue?: PromiseOrValue<InputType>) {\n super();\n this.#value = from(() => this.getDefaultValue());\n if (initialValue) {\n this.#value = this.deriveFromPromiseOrValue(initialValue, this.#value);\n }\n }\n\n set(input: PromiseOrValue<InputType>): void {\n this.#value = this.deriveFromPromiseOrValue(input, this.#value);\n\n const sourceEventDetail: SourceEventDetail<OutputType> = {\n sourceProp: this,\n value: this.#value,\n generation: ++globalSourceGeneration as Generation,\n };\n this.markStale(\n new CustomEvent<SourceEventDetail<OutputType>>(\"stale\", {\n detail: sourceEventDetail,\n }),\n );\n }\n\n async get(): Promise<OutputType> {\n return this.#value;\n }\n\n protected async deriveFromPromiseOrValue(\n input: PromiseOrValue<InputType>,\n oldValuePromise: Promise<OutputType>,\n ): Promise<OutputType> {\n return this.derive(await input, oldValuePromise);\n }\n\n // TODO: add an indirect layer to cache the derivation?\n protected abstract derive(\n input: InputType,\n oldValuePromise: Promise<OutputType>,\n ): PromiseOrValue<OutputType>;\n}\n\nexport abstract class SimpleTwistyPropSource<\n SimpleType,\n> extends TwistyPropSource<SimpleType> {\n protected override derive(input: SimpleType): PromiseOrValue<SimpleType> {\n return input;\n }\n}\n\n// TODO: Can we support `null` as a valid output value without loosening type\n// safety?\nexport const NO_VALUE = Symbol(\"no value\");\nexport type NoValueType = typeof NO_VALUE;\n\nexport abstract class TwistyPropDerived<\n InputTypes extends InputRecord,\n OutputType,\n> extends TwistyPropParent<OutputType> {\n // cachedInputs:\n #parents: InputProps<InputTypes>;\n\n constructor(\n parents: InputProps<InputTypes>,\n protected userVisibleErrorTracker?: UserVisibleErrorTracker,\n ) {\n super();\n this.#parents = parents;\n for (const parent of Object.values(parents)) {\n (\n parent as TwistyPropDerived<InputProps<InputTypes>, OutputType>\n ).addChild(this);\n }\n }\n\n #cachedLastSuccessfulCalculation: {\n inputs: InputTypes;\n output: Promise<OutputType>;\n generation: number;\n } | null = null;\n\n #cachedLatestGenerationCalculation: {\n output: Promise<OutputType>;\n generation: number;\n } | null = null;\n\n public async get(): Promise<OutputType> {\n const generation = this.lastSourceGeneration;\n\n if (this.#cachedLatestGenerationCalculation?.generation === generation) {\n return this.#cachedLatestGenerationCalculation.output;\n }\n\n const latestGenerationCalculation = {\n generation,\n output: this.#cacheDerive(\n this.#getParents(),\n generation,\n this.#cachedLastSuccessfulCalculation,\n ),\n };\n this.#cachedLatestGenerationCalculation = latestGenerationCalculation;\n\n this.userVisibleErrorTracker?.reset();\n return latestGenerationCalculation.output;\n }\n\n async #getParents(): Promise<InputTypes> {\n const inputValuePromises: InputPromises<InputRecord> = {} as any; // TODO\n for (const [key, parent] of Object.entries(this.#parents)) {\n (inputValuePromises as Record<string, Promise<unknown>>)[key] = (\n parent as TwistyPropParent<unknown>\n ).get();\n }\n\n const inputs: InputTypes = {} as any; // TODO\n for (const key in this.#parents) {\n inputs[key] = (await (\n inputValuePromises as Record<string, Promise<unknown>>\n )[key]) as any;\n }\n return inputs;\n }\n\n async #cacheDerive(\n inputsPromise: PromiseOrValue<InputTypes>,\n generation: number,\n cachedLatestGenerationCalculation: {\n inputs: InputTypes;\n output: Promise<OutputType>;\n generation: number;\n } | null = null,\n ): Promise<OutputType> {\n const inputs = await inputsPromise;\n\n const cache = (output: OutputType): OutputType => {\n this.#cachedLastSuccessfulCalculation = {\n inputs,\n output: Promise.resolve(output),\n generation,\n };\n return output;\n };\n\n if (!cachedLatestGenerationCalculation) {\n return cache(await this.derive(inputs));\n }\n\n const cachedInputs = cachedLatestGenerationCalculation.inputs;\n for (const key in this.#parents) {\n const parent = this.#parents[key];\n if (!parent.canReuse(inputs[key], cachedInputs[key])) {\n return cache(await this.derive(inputs));\n }\n }\n\n return cachedLatestGenerationCalculation.output;\n }\n\n protected abstract derive(input: InputTypes): PromiseOrValue<OutputType>;\n}\n\nexport class FreshListenerManager {\n #disconnectionFunctions: (() => void)[] = [];\n\n addListener<T>(\n prop: TwistyPropParent<T>,\n listener: (value: T) => void,\n ): void {\n let disconnected = false;\n const wrappedListener = (value: T) => {\n if (disconnected) {\n // TODO\n // console.warn(\"Should be disconnected!\");\n return;\n }\n listener(value);\n };\n\n prop.addFreshListener(wrappedListener);\n\n this.#disconnectionFunctions.push(() => {\n prop.removeFreshListener(wrappedListener);\n disconnected = true;\n });\n }\n\n // TODO: Figure out the signature to let us do overloads\n /** @deprecated */\n public addMultiListener3<U, V, W>(\n props: [TwistyPropParent<U>, TwistyPropParent<V>, TwistyPropParent<W>],\n listener: (values: [U, V, W]) => void,\n ): void {\n this.addMultiListener(props as any, listener as any); // TODO\n }\n public addMultiListener<U, V>(\n props: [TwistyPropParent<U>, TwistyPropParent<V>],\n listener: (values: [U, V]) => void,\n ) {\n let disconnected = false;\n\n // We're going to get one initial call per prop. We'll ignore all but one.\n let initialIgnoresLeft = props.length - 1;\n const wrappedListener = async (_: any) => {\n if (initialIgnoresLeft > 0) {\n initialIgnoresLeft--;\n return;\n }\n if (disconnected) {\n // TODO\n // console.warn(\"Should be disconnected!\");\n return;\n }\n // We rely on `TwistyProp` caching to give us the full set of latest\n // values efficiently.\n const promises = (props as TwistyPropParent<any>[]).map((prop) =>\n prop.get(),\n );\n const values = await Promise.all(promises);\n listener(values as any); // TODO: fix up types\n };\n\n for (const prop of props) {\n prop.addFreshListener(wrappedListener);\n }\n\n this.#disconnectionFunctions.push(() => {\n for (const prop of props) {\n prop.removeFreshListener(wrappedListener);\n }\n disconnected = true;\n });\n }\n\n public disconnect(): void {\n for (const disconnectionFunction of this.#disconnectionFunctions) {\n disconnectionFunction();\n }\n }\n}\n", "// Workarounds for `node`.\n// TODO: figure out how to remove this.\n\n// This stub does not need to be callable, just constructable to satisfy the `node` loader.\nclass HTMLElementStub {}\n\nlet HTMLElementShim: typeof HTMLElement;\nif (globalThis.HTMLElement) {\n HTMLElementShim = globalThis.HTMLElement;\n} else {\n HTMLElementShim = HTMLElementStub as any;\n}\n\nexport { HTMLElementShim };\n\nclass CustomElementsStub {\n define(): void {\n // nothing\n }\n}\n\nlet customElementsShim: typeof customElements;\n\nif (globalThis.customElements) {\n customElementsShim = globalThis.customElements;\n} else {\n customElementsShim = new CustomElementsStub() as any;\n}\n\nexport { customElementsShim };\n\nlet cssStyleSheetShim: typeof CSSStyleSheet;\n\nclass CSSStyleSheetStub {\n replaceSync(): void {\n // nothing\n }\n}\n\nif (globalThis.CSSStyleSheet) {\n cssStyleSheetShim = globalThis.CSSStyleSheet;\n} else {\n cssStyleSheetShim = CSSStyleSheetStub as any;\n}\n\nexport { cssStyleSheetShim };\n", "import {\n customElementsShim,\n HTMLElementShim,\n} from \"./node-custom-element-shims\";\n\n// - Wrapped element\n// - Shadow root\n// - Content wrapper\nexport class ManagedCustomElement extends HTMLElementShim {\n public readonly shadow: ShadowRoot; // TODO: hide this\n public readonly contentWrapper: HTMLDivElement; // TODO: can we get rid of this wrapper?\n\n constructor(options?: { mode?: \"open\" | \"closed\" }) {\n super();\n this.shadow = this.attachShadow({ mode: options?.mode ?? \"closed\" });\n\n this.contentWrapper = document.createElement(\"div\");\n this.contentWrapper.classList.add(\"wrapper\");\n this.shadow.appendChild(this.contentWrapper);\n }\n\n // Add the source, if not already added.\n // Returns the existing if it's already on the element.\n protected addCSS(cssSource: CSSStyleSheet): void {\n this.shadow.adoptedStyleSheets.push(cssSource);\n }\n\n protected removeCSS(cssSource: CSSStyleSheet) {\n const cssIndex = this.shadow.adoptedStyleSheets.indexOf(cssSource);\n if (typeof cssIndex !== \"undefined\") {\n this.shadow.adoptedStyleSheets.splice(cssIndex, cssIndex + 1);\n }\n }\n\n public addElement<T extends Node>(element: T): T {\n return this.contentWrapper.appendChild(element);\n }\n\n public prependElement<T extends Node>(element: T): void {\n this.contentWrapper.prepend(element);\n }\n\n public removeElement<T extends Node>(element: T): T {\n return this.contentWrapper.removeChild(element);\n }\n}\n\ncustomElementsShim.define(\n \"twisty-managed-custom-element\",\n ManagedCustomElement,\n);\n", "import type { MillisecondTimestamp } from \"./AnimationTypes\";\n\n// Debounces `requestAnimationFrame()`.\nexport class RenderScheduler {\n private animFrameID: number | null = null;\n private animFrame = this.animFrameWrapper.bind(this);\n constructor(private callback: (timestamp: MillisecondTimestamp) => void) {}\n\n requestIsPending(): boolean {\n return !!this.animFrameID;\n }\n\n requestAnimFrame(): void {\n if (!this.animFrameID) {\n this.animFrameID = requestAnimationFrame(this.animFrame);\n }\n }\n\n cancelAnimFrame(): void {\n if (this.animFrameID) {\n cancelAnimationFrame(this.animFrameID);\n this.animFrameID = 0;\n }\n }\n\n private animFrameWrapper(timestamp: DOMHighResTimeStamp): void {\n this.animFrameID = 0;\n this.callback(timestamp as MillisecondTimestamp);\n }\n}\n\n// An interface for classes to use to expose their scheduling.\nexport interface Schedulable {\n scheduleRender(): void;\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\n// TODO: turn these maps into lists?\nexport const hintFaceletStyles = {\n floating: true, // default\n none: true,\n};\nexport type HintFaceletStyle = keyof typeof hintFaceletStyles;\nexport type HintFaceletStyleWithAuto = HintFaceletStyle | \"auto\";\n\nexport class HintFaceletProp extends SimpleTwistyPropSource<HintFaceletStyleWithAuto> {\n getDefaultValue(): HintFaceletStyleWithAuto {\n return \"auto\";\n }\n}\n", "export const TAU = Math.PI * 2;\nexport const DEGREES_PER_RADIAN = 360 / TAU;\n", "/**\n * @author mrdoob / http://mrdoob.com/\n * ESM conversion by Lucas Garron, 2021-12-21\n */\n\nconst performance:\n | null\n | (Performance & {\n memory?: {\n usedJSHeapSize: number;\n jsHeapSizeLimit: number;\n };\n }) = globalThis.performance;\n\nexport class Stats {\n mode = 0;\n\n dom = document.createElement(\"div\");\n\n constructor() {\n this.dom.style.cssText =\n \"position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000\";\n this.dom.addEventListener(\n \"click\",\n (event) => {\n event.preventDefault();\n this.showPanel(++this.mode % this.dom.children.length);\n },\n false,\n );\n\n this.showPanel(0);\n }\n\n addPanel(panel: StatsPanel): StatsPanel {\n this.dom.appendChild(panel.dom);\n return panel;\n }\n\n showPanel(id: number): void {\n for (let i = 0; i < this.dom.children.length; i++) {\n (this.dom.children[i] as HTMLElement).style.display =\n i === id ? \"block\" : \"none\";\n }\n\n this.mode = id;\n }\n\n beginTime = (performance || Date).now();\n prevTime = this.beginTime;\n frames = 0;\n\n fpsPanel = this.addPanel(new StatsPanel(\"FPS\", \"#0ff\", \"#002\"));\n msPanel = this.addPanel(new StatsPanel(\"MS\", \"#0f0\", \"#020\"));\n memPanel = performance?.memory\n ? this.addPanel(new StatsPanel(\"MB\", \"#f08\", \"#201\"))\n : null;\n REVISION = 16;\n\n begin() {\n this.beginTime = (performance || Date).now();\n }\n\n end() {\n this.frames++;\n\n const time = (performance || Date).now();\n\n this.msPanel.update(time - this.beginTime, 200);\n\n if (time >= this.prevTime + 1000) {\n this.fpsPanel.update((this.frames * 1000) / (time - this.prevTime), 100);\n\n this.prevTime = time;\n this.frames = 0;\n\n if (this.memPanel) {\n const memory = performance!.memory!;\n this.memPanel.update(\n memory.usedJSHeapSize / 1048576,\n memory.jsHeapSizeLimit / 1048576,\n );\n }\n }\n\n return time;\n }\n\n update() {\n this.beginTime = this.end();\n }\n}\n\nconst PR = Math.round(globalThis?.window?.devicePixelRatio ?? 1);\n\nconst WIDTH = 80 * PR;\nconst HEIGHT = 48 * PR;\nconst TEXT_X = 3 * PR;\nconst TEXT_Y = 2 * PR;\nconst GRAPH_X = 3 * PR;\nconst GRAPH_Y = 15 * PR;\nconst GRAPH_WIDTH = 74 * PR;\nconst GRAPH_HEIGHT = 30 * PR;\n\nexport class StatsPanel {\n min = Infinity;\n max = 0;\n dom = document.createElement(\"canvas\");\n context = this.dom.getContext(\"2d\")!;\n constructor(\n private name: string,\n private fg: string,\n private bg: string,\n ) {\n this.dom.width = WIDTH;\n this.dom.height = HEIGHT;\n this.dom.style.cssText = \"width:80px;height:48px\";\n\n this.context.font = `bold ${9 * PR}px Helvetica,Arial,sans-serif`;\n this.context.textBaseline = \"top\";\n\n this.context.fillStyle = bg;\n this.context.fillRect(0, 0, WIDTH, HEIGHT);\n\n this.context.fillStyle = fg;\n this.context.fillText(name, TEXT_X, TEXT_Y);\n this.context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);\n\n this.context.fillStyle = bg;\n this.context.globalAlpha = 0.9;\n this.context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);\n }\n\n update(value: number, maxValue: number) {\n this.min = Math.min(this.min, value);\n this.max = Math.max(this.max, value);\n\n this.context.fillStyle = this.bg;\n this.context.globalAlpha = 1;\n this.context.fillRect(0, 0, WIDTH, GRAPH_Y);\n this.context.fillStyle = this.fg;\n this.context.fillText(\n `${Math.round(value)} ${this.name} (${Math.round(this.min)}-${Math.round(\n this.max,\n )})`,\n TEXT_X,\n TEXT_Y,\n );\n\n this.context.drawImage(\n this.dom,\n GRAPH_X + PR,\n GRAPH_Y,\n GRAPH_WIDTH - PR,\n GRAPH_HEIGHT,\n GRAPH_X,\n GRAPH_Y,\n GRAPH_WIDTH - PR,\n GRAPH_HEIGHT,\n );\n\n this.context.fillRect(\n GRAPH_X + GRAPH_WIDTH - PR,\n GRAPH_Y,\n PR,\n GRAPH_HEIGHT,\n );\n\n this.context.fillStyle = this.bg;\n this.context.globalAlpha = 0.9;\n this.context.fillRect(\n GRAPH_X + GRAPH_WIDTH - PR,\n GRAPH_Y,\n PR,\n Math.round((1 - value / maxValue) * GRAPH_HEIGHT),\n );\n }\n}\n", "// TODO can we remove the cached proxy?\n\n// In theory we can, but we've run into situations where imports are not properly cached.\nlet cachedConstructorProxy: Promise<\n typeof import(\"./dynamic-entries/twisty-dynamic-3d\")\n> | null = null;\n\nexport async function bulk3DCode(): Promise<\n typeof import(\"./dynamic-entries/twisty-dynamic-3d\")\n> {\n return (cachedConstructorProxy ??= import(\n \"./dynamic-entries/twisty-dynamic-3d\"\n ));\n}\n", "let globalPixelRatioOverride: number | null = null;\nexport function setGlobalPixelRatioOverride(override: number | null): void {\n globalPixelRatioOverride = override;\n}\n\n// TODO: Handle if you move across screens?\nexport function pixelRatio(): number {\n return globalPixelRatioOverride ?? (devicePixelRatio || 1);\n}\n", "// export class Drag() {\n\n// }\n\ninterface DragInfo {\n attachedInfo: Record<any, any>;\n hasMoved: boolean;\n lastClientX: number;\n lastClientY: number;\n lastTimeStamp: number;\n}\n\ntype PointerID = number;\n\nexport interface DragMovementInfo {\n attachedInfo: Record<any, any>;\n movementX: number;\n movementY: number;\n elapsedMs: number;\n}\n\nexport interface UpInfo {\n attachedInfo: Record<any, any>;\n}\n\nexport interface PressInfo {\n normalizedX: number;\n normalizedY: number;\n rightClick: boolean;\n keys: {\n // TODO: group these\n altKey: boolean;\n ctrlOrMetaKey: boolean;\n shiftKey: boolean;\n };\n}\n\n// Chrome can report movements as low as `0.0000152587890625` even if the cursor did not move at all. So we need a treshold instead.\nconst MOVEMENT_EPSILON = 0.1; // px\n\nexport class DragTracker extends EventTarget {\n #dragInfoMap: Map<PointerID, DragInfo> = new Map();\n\n constructor(public readonly target: HTMLElement) {\n super();\n }\n\n // Idempotent\n start() {\n this.addTargetListener(\"pointerdown\", this.onPointerDown.bind(this));\n // Prevent right-click on desktop (only tested on macOS Chrome/Safari/Firefox) so we can detect right-click moves.\n // TODO: Can we do this selectively, e.g. only on the puzzle? That way we could allow right-click to download the canvas. Unfortunately, it would probably require a sync calculation.\n this.addTargetListener(\"contextmenu\", (e: MouseEvent) => {\n e.preventDefault();\n });\n // Prevent touch scrolling (preventing default on `pointermove` doesn't work).\n this.addTargetListener(\"touchmove\", (e: PointerEvent) =>\n e.preventDefault(),\n );\n // Prevent zooming on double-tap (iOS).\n // This is because `dblclick` works to zoom in, but does *not* work to zoom out. So the user can get stuck zoomed into the player without a way to zoom out.\n this.addTargetListener(\"dblclick\", (e: MouseEvent) => e.preventDefault());\n }\n\n // Idempotent\n stop(): void {\n for (const [eventType, listener] of this.#targetListeners.entries()) {\n this.target.removeEventListener(\n eventType,\n listener as unknown as EventListener,\n ); // TODO\n }\n this.#targetListeners.clear();\n this.#lazyListenersRegistered = false;\n }\n\n #targetListeners = new Map<\n string,\n ((e: MouseEvent) => any) | ((e: PointerEvent) => any)\n >();\n addTargetListener(\n eventType: string,\n listener: ((e: MouseEvent) => any) | ((e: PointerEvent) => any),\n ) {\n if (!this.#targetListeners.has(eventType)) {\n this.target.addEventListener(\n eventType,\n listener as unknown as EventListener, // TODO\n );\n this.#targetListeners.set(eventType, listener);\n }\n }\n\n // This allows us to avoid getting a callback every time the pointer moves over the canvas, until we have a down event.\n // 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.\n #lazyListenersRegistered: boolean = false;\n #registerLazyListeners(): void {\n if (this.#lazyListenersRegistered) {\n return;\n }\n this.addTargetListener(\"pointermove\", this.onPointerMove.bind(this)); // TODO: only register this after pointer down.\n this.addTargetListener(\"pointerup\", this.onPointerUp.bind(this));\n this.#lazyListenersRegistered = true;\n }\n\n #clear(e: PointerEvent): void {\n this.#dragInfoMap.delete(e.pointerId);\n }\n\n // `null`: means: ignore this result (no movement, or not\n #trackDrag(e: PointerEvent): {\n movementInfo: DragMovementInfo | null;\n hasMoved: boolean;\n } {\n // TODO: Find a way to detect if this is an active press, in a way that works cross-platform.\n // if (e.buttons === 0) {\n // return { movementInfo: null, hasMoved: false };\n // }\n const existing = this.#dragInfoMap.get(e.pointerId);\n if (!existing) {\n return { movementInfo: null, hasMoved: false };\n }\n // We would try to use `e.movementX`/`e.movementY`, except Safari:\n // - Does not have those values on i[Pad]OS.\n // - Will always report `0` for these values on macOS.\n // https://bugs.webkit.org/show_bug.cgi?id=220194\n //\n // The following are all insufficiently powerful for detecting the Safari `0` bug:\n // - `\"movementX\" in e`\n // - `e.movementX !== \"undefined\"`\n // - `e.hasOwnProperty(\"movementX\")`\n\n let movementInfo: DragMovementInfo;\n if ((e.movementX ?? 0) !== 0 || (e.movementY ?? 0) !== 0) {\n // We optimistically try to catch sub-pixel movements in Chrome.\n movementInfo = {\n attachedInfo: existing.attachedInfo,\n movementX: e.movementX,\n movementY: e.movementY,\n elapsedMs: e.timeStamp - existing.lastTimeStamp,\n };\n } else {\n movementInfo = {\n attachedInfo: existing.attachedInfo,\n movementX: e.clientX - existing.lastClientX,\n movementY: e.clientY - existing.lastClientY,\n elapsedMs: e.timeStamp - existing.lastTimeStamp,\n };\n }\n existing.lastClientX = e.clientX;\n existing.lastClientY = e.clientY;\n existing.lastTimeStamp = e.timeStamp;\n if (\n Math.abs(movementInfo.movementX) < MOVEMENT_EPSILON &&\n Math.abs(movementInfo.movementY) < MOVEMENT_EPSILON\n ) {\n return { movementInfo: null, hasMoved: existing.hasMoved };\n } else {\n existing.hasMoved = true;\n return { movementInfo, hasMoved: existing.hasMoved };\n }\n }\n\n private onPointerDown(e: PointerEvent) {\n this.#registerLazyListeners();\n const newDragInfo: DragInfo = {\n attachedInfo: {},\n hasMoved: false,\n lastClientX: e.clientX,\n lastClientY: e.clientY,\n lastTimeStamp: e.timeStamp,\n };\n this.#dragInfoMap.set(e.pointerId, newDragInfo);\n this.target.setPointerCapture(e.pointerId);\n }\n\n private onPointerMove(e: PointerEvent) {\n const movementInfo = this.#trackDrag(e).movementInfo;\n if (movementInfo) {\n e.preventDefault();\n this.dispatchEvent(\n new CustomEvent(\"move\", {\n detail: movementInfo,\n }),\n );\n }\n }\n\n private onPointerUp(e: PointerEvent) {\n const trackDragResult = this.#trackDrag(e);\n const existing = this.#dragInfoMap.get(e.pointerId)!; // TODO\n this.#clear(e);\n this.target.releasePointerCapture(e.pointerId); // TODO: unnecessary?\n let event: CustomEvent;\n if (trackDragResult.hasMoved) {\n // TODO: send proper movement/momentum since last move event.\n event = new CustomEvent<UpInfo>(\"up\", {\n detail: { attachedInfo: existing.attachedInfo },\n });\n } else {\n const { altKey, ctrlKey, metaKey, shiftKey } = e;\n event = new CustomEvent<PressInfo>(\"press\", {\n detail: {\n normalizedX: (e.offsetX / this.target.offsetWidth) * 2 - 1,\n normalizedY: 1 - (e.offsetY / this.target.offsetHeight) * 2,\n rightClick: !!(e.button & 2),\n keys: {\n altKey,\n ctrlOrMetaKey: ctrlKey || metaKey,\n shiftKey,\n },\n },\n });\n }\n this.dispatchEvent(event);\n }\n}\n", "// TODO: https://stackoverflow.com/a/40443642\n\n// let shareAllNewRenderers: boolean = false;\n\n// // WARNING: The current shared renderer implementation is not every efficient.\n// // Avoid using for players that are likely to have dimensions approaching 1 megapixel or higher.\n// // TODO: use a dedicated renderer while fullscreen?\n// export function experimentalSetShareAllNewRenderers(share: boolean): void {\n// shareAllNewRenderers = share;\n// }\n\n// const sharedRenderer: WebGLRenderer | null = null;\n\nimport { bulk3DCode } from \"../../heavy-code-imports/3d\";\nimport type {\n Camera,\n LinearSRGBColorSpace,\n Scene,\n WebGLRenderer,\n} from \"../../heavy-code-imports/three-types\";\nimport { pixelRatio } from \"../canvas\";\n\nconst renderers: Promise<WebGLRenderer>[] = [];\n\n// Render result is guaranteed to be available synchronously at resolution time.\nexport async function rawRenderPooled(\n width: number,\n height: number,\n scene: Scene,\n camera: Camera,\n): Promise<HTMLCanvasElement> {\n // At most one in the pool for now.\n if (renderers.length === 0) {\n renderers.push(newRenderer());\n }\n const renderer = await renderers[0];\n // TODO: scissoring\n renderer.setSize(width, height); // TODO: is it faster if we cache values and only call this when necessary?\n renderer.render(scene, camera);\n\n return renderer.domElement;\n}\n\n// let haveSet = false;\nexport async function renderPooled(\n width: number,\n height: number,\n canvas: HTMLCanvasElement,\n scene: Scene,\n camera: Camera,\n): Promise<void> {\n if (width === 0 || height === 0) {\n return;\n }\n // At most one in the pool for now.\n if (renderers.length === 0) {\n renderers.push(newRenderer());\n }\n\n const rendererCanvas = await rawRenderPooled(width, height, scene, camera);\n\n // TODO: Should we cache this? Seems to take about 0.0001ms to get.\n const context = canvas.getContext(\"2d\")!;\n context.clearRect(0, 0, canvas.width, canvas.height);\n context.drawImage(rendererCanvas, 0, 0);\n}\n\n// Workaround to avoid an import of `three`.\nconst linearSRGBColorSpace =\n \"srgb-linear\" satisfies typeof LinearSRGBColorSpace;\n\nexport async function newRenderer(): Promise<WebGLRenderer> {\n const rendererConstructor = (await bulk3DCode()).ThreeWebGLRenderer;\n const renderer = new rendererConstructor({\n antialias: true,\n alpha: true,\n });\n renderer.outputColorSpace = linearSRGBColorSpace; // TODO(https://github.com/cubing/cubing.js/issues/308): remove this\n renderer.setPixelRatio(pixelRatio());\n return renderer;\n}\n", "// The `position` values are a hack for a bug in Safari where the canvas either\n// grows infinitely, or takes up the full `fr` of any encompassing grid (making\n// the contents of that element e.g. over 100% of its height). `contain:\n// content` is a good fix for this, but there is no indication that Safari will\n// support it soon. https://developer.mozilla.org/en-US/docs/Web/CSS/contain\n\nimport { cssStyleSheetShim } from \"../node-custom-element-shims\";\n\nexport const twisty3DVantageCSS = new cssStyleSheetShim();\ntwisty3DVantageCSS.replaceSync(\n `\n:host {\n width: 384px;\n height: 256px;\n display: grid;\n}\n\n.wrapper {\n width: 100%;\n height: 100%;\n display: grid;\n overflow: hidden;\n place-content: center;\n contain: strict;\n}\n\n.loading {\n width: 4em;\n height: 4em;\n border-radius: 2.5em;\n border: 0.5em solid rgba(0, 0, 0, 0);\n border-top: 0.5em solid rgba(0, 0, 0, 0.7);\n border-right: 0.5em solid rgba(0, 0, 0, 0.7);\n animation: fade-in-delayed 4s, rotate 1s linear infinite;\n}\n\n@keyframes fade-in-delayed {\n 0% { opacity: 0; }\n 25% {opacity: 0; }\n 100% { opacity: 1; }\n}\n\n@keyframes rotate {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n/* TODO: This is due to stats hack. Replace with \\`canvas\\`. */\n.wrapper > canvas {\n max-width: 100%;\n max-height: 100%;\n animation: fade-in 0.25s ease-in;\n}\n\n@keyframes fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.wrapper.invisible {\n opacity: 0;\n}\n\n.wrapper.drag-input-enabled > canvas {\n cursor: grab;\n}\n\n.wrapper.drag-input-enabled > canvas:active {\n cursor: grabbing;\n}\n`,\n);\n", "import type { Vector3 } from \"three/src/Three.js\";\nimport { RenderScheduler } from \"../../controllers/RenderScheduler\";\nimport { bulk3DCode } from \"../../heavy-code-imports/3d\";\nimport type { OrbitCoordinates } from \"../../model/props/viewer/OrbitCoordinatesRequestProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport type { DragMovementInfo, DragTracker } from \"./DragTracker\";\nimport { DEGREES_PER_RADIAN } from \"./TAU\";\n\nconst INERTIA_DEFAULT: boolean = true;\n\nconst INERTIA_DURATION_MS = 500;\n// If the first inertial render is this long after the last move, we assume the\n// user has halted the cursor and we consider inertia to have \"timed out\". We\n// never begin animating the inertia.\nconst INERTIA_TIMEOUT_MS = 50;\n\nconst VERTICAL_MOVEMENT_BASE_SCALE = 0.75;\n\n// progress is from 0 to 1.\nfunction momentumScale(progress: number) {\n // This is the exponential curve flipped so that\n // - The slope at progress = 0 is 1 (this corresponds to \"x = 1\" on the normal\n // curve).\n // - The scale exponentially \"decays\" until progress = 1.\n // This means the scale at the end will be about 0.418\n return (Math.exp(1 - progress) - (1 - progress)) / (1 - Math.E) + 1;\n}\n\nclass Inertia {\n private scheduler = new RenderScheduler(this.render.bind(this));\n private lastTimestamp: number;\n constructor(\n private startTimestamp: number,\n private momentumX: number,\n private momentumY: number,\n private callback: (movementX: number, movementY: number) => void,\n ) {\n this.scheduler.requestAnimFrame();\n this.lastTimestamp = startTimestamp;\n }\n\n private render(now: DOMHighResTimeStamp) {\n const progressBefore =\n (this.lastTimestamp - this.startTimestamp) / INERTIA_DURATION_MS;\n const progressAfter = Math.min(\n 1,\n (now - this.startTimestamp) / INERTIA_DURATION_MS,\n );\n\n if (\n progressBefore === 0 &&\n progressAfter > INERTIA_TIMEOUT_MS / INERTIA_DURATION_MS\n ) {\n // The user has already paused for a while. Don't start any inertia.\n return;\n }\n\n const delta = momentumScale(progressAfter) - momentumScale(progressBefore);\n\n // TODO: For now, we only carry horizontal momentum. If this should stay, we\n // can remove the plumbing for the Y dimension.\n this.callback(this.momentumX * delta * 1000, this.momentumY * delta * 1000);\n\n if (progressAfter < 1) {\n this.scheduler.requestAnimFrame();\n }\n this.lastTimestamp = now;\n }\n}\n\nexport async function positionToOrbitCoordinates(\n position: Vector3,\n): Promise<OrbitCoordinates> {\n const spherical = new (await bulk3DCode()).ThreeSpherical();\n spherical.setFromVector3(position);\n return {\n latitude: 90 - spherical.phi * DEGREES_PER_RADIAN,\n longitude: spherical.theta * DEGREES_PER_RADIAN,\n distance: spherical.radius,\n };\n}\n\ninterface TwistyOrbitControlsDragAttachedInfo {\n lastTemperedX: number;\n lastTemperedY: number;\n timestamp: number;\n}\n\n// TODO: change mouse cursor while moving.\nexport class TwistyOrbitControls {\n /** @deprecated */\n experimentalInertia: boolean = INERTIA_DEFAULT;\n private onMovementBound = this.onMovement.bind(this);\n public experimentalHasBeenMoved: boolean = false;\n constructor(\n private model: TwistyPlayerModel,\n private mirror: boolean,\n private canvas: HTMLCanvasElement,\n private dragTracker: DragTracker,\n ) {\n this.dragTracker.addEventListener(\n \"move\",\n this.onMove.bind(this) as any as EventListener, // TODO: https://github.com/microsoft/TypeScript/issues/28357\n );\n this.dragTracker.addEventListener(\n \"up\",\n this.onUp.bind(this) as any as EventListener, // TODO: https://github.com/microsoft/TypeScript/issues/28357\n );\n }\n\n // f is the fraction of the canvas traversed per ms.\n temperMovement(f: number): number {\n // This is scaled to be linear for small values, but to reduce large values\n // by a significant factor.\n return (Math.sign(f) * Math.log(Math.abs(f * 10) + 1)) / 6;\n }\n\n onMove(e: CustomEvent<DragMovementInfo>): void {\n e.detail.attachedInfo ??= {};\n\n const { temperedX, temperedY } = this.onMovement(\n e.detail.movementX,\n e.detail.movementY,\n );\n const attachedInfo = e.detail\n .attachedInfo as TwistyOrbitControlsDragAttachedInfo;\n attachedInfo.lastTemperedX = temperedX * 10;\n attachedInfo.lastTemperedY = temperedY * 10;\n attachedInfo.timestamp = e.timeStamp; // TODO\n }\n\n onMovement(\n movementX: number,\n movementY: number,\n ): {\n temperedX: number;\n temperedY: number;\n } {\n const scale = this.mirror ? -1 : 1;\n\n // TODO: refactor\n const minDim = Math.min(this.canvas.offsetWidth, this.canvas.offsetHeight);\n\n const temperedX = this.temperMovement(movementX / minDim);\n const temperedY = this.temperMovement(\n (movementY / minDim) * VERTICAL_MOVEMENT_BASE_SCALE,\n );\n this.model.twistySceneModel.orbitCoordinatesRequest.set(\n (async () => {\n const prevCoords =\n await this.model.twistySceneModel.orbitCoordinates.get();\n\n const newCoords = {\n latitude:\n prevCoords.latitude + 2 * temperedY * DEGREES_PER_RADIAN * scale,\n longitude: prevCoords.longitude - 2 * temperedX * DEGREES_PER_RADIAN,\n };\n return newCoords;\n })(),\n );\n return { temperedX, temperedY };\n }\n\n onUp(e: CustomEvent<DragMovementInfo>): void {\n e.preventDefault();\n if (\n \"lastTemperedX\" in e.detail.attachedInfo &&\n \"lastTemperedY\" in e.detail.attachedInfo &&\n \"timestamp\" in e.detail.attachedInfo &&\n e.timeStamp - e.detail.attachedInfo[\"timestamp\"] < 60 // TODO\n ) {\n new Inertia(\n e.timeStamp, // TODO\n (e.detail.attachedInfo as TwistyOrbitControlsDragAttachedInfo)\n .lastTemperedX,\n (e.detail.attachedInfo as TwistyOrbitControlsDragAttachedInfo)\n .lastTemperedY,\n this.onMovementBound,\n ); // TODO: cancel inertia\n }\n }\n}\n", "import type { PerspectiveCamera, WebGLRenderer } from \"three/src/Three.js\";\nimport { Stats } from \"../../../vendor/mit/three/examples/jsm/libs/stats.modified.module\";\nimport { RenderScheduler } from \"../../controllers/RenderScheduler\";\nimport { twistyDebugGlobals } from \"../../debug\";\nimport { bulk3DCode } from \"../../heavy-code-imports/3d\";\nimport { StaleDropper } from \"../../model/PromiseFreshener\";\nimport type { DragInputMode } from \"../../model/props/puzzle/state/DragInputProp\";\nimport type { TwistyPropParent } from \"../../model/props/TwistyProp\";\nimport type { OrbitCoordinates } from \"../../model/props/viewer/OrbitCoordinatesRequestProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { pixelRatio } from \"../canvas\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { DragTracker, type PressInfo } from \"./DragTracker\";\nimport { newRenderer, renderPooled } from \"./RendererPool\";\nimport { DEGREES_PER_RADIAN } from \"./TAU\";\nimport type { Twisty3DSceneWrapper } from \"./Twisty3DSceneWrapper\";\nimport { twisty3DVantageCSS } from \"./Twisty3DVantage.css\";\nimport { TwistyOrbitControls } from \"./TwistyOrbitControls\";\n\nexport async function setCameraFromOrbitCoordinates(\n camera: PerspectiveCamera,\n orbitCoordinates: OrbitCoordinates,\n backView: boolean = false,\n): Promise<void> {\n const spherical = new (await bulk3DCode()).ThreeSpherical(\n orbitCoordinates.distance,\n (90 - (backView ? -1 : 1) * orbitCoordinates.latitude) / DEGREES_PER_RADIAN,\n ((backView ? 180 : 0) + orbitCoordinates.longitude) / DEGREES_PER_RADIAN,\n );\n spherical.makeSafe();\n camera.position.setFromSpherical(spherical);\n camera.lookAt(0, 0, 0);\n}\n\nlet dedicatedRenderersSoFar = 0;\nconst DEFAULT_MAX_DEDICATED_RENDERERS = 2; // This allows for a front view and a back view (or two separate front views).\nlet sharingRenderers = false;\nfunction shareRenderer(): boolean {\n if (twistyDebugGlobals.shareAllNewRenderers !== \"auto\") {\n if (!twistyDebugGlobals.shareAllNewRenderers) {\n dedicatedRenderersSoFar++;\n }\n return twistyDebugGlobals.shareAllNewRenderers !== \"never\";\n }\n if (dedicatedRenderersSoFar < DEFAULT_MAX_DEDICATED_RENDERERS) {\n dedicatedRenderersSoFar++;\n return false;\n } else {\n sharingRenderers = true;\n return true;\n }\n}\n\nexport function haveStartedSharingRenderers(): boolean {\n return sharingRenderers;\n}\n\nexport class Twisty3DVantage extends ManagedCustomElement {\n scene: Twisty3DSceneWrapper | null = null;\n\n stats: Stats | null = null;\n\n private rendererIsShared: boolean = shareRenderer();\n\n loadingElement: HTMLDivElement | null = null;\n constructor(\n private model?: TwistyPlayerModel,\n scene?: Twisty3DSceneWrapper,\n private options?: { backView?: boolean },\n ) {\n super();\n this.scene = scene ?? null;\n\n this.loadingElement = this.addElement(document.createElement(\"div\"));\n this.loadingElement.classList.add(\"loading\");\n\n if (twistyDebugGlobals.showRenderStats) {\n this.stats = new Stats();\n this.stats.dom.style.position = \"absolute\";\n this.contentWrapper.appendChild(this.stats.dom);\n }\n }\n\n async connectedCallback(): Promise<void> {\n this.addCSS(twisty3DVantageCSS);\n this.addElement((await this.canvasInfo()).canvas);\n\n this.#onResize();\n const observer = new ResizeObserver(this.#onResize.bind(this));\n observer.observe(this.contentWrapper);\n this.orbitControls(); // Instantiate orbit controls\n this.#setupBasicPresses();\n\n this.scheduleRender();\n }\n\n async #setupBasicPresses(): Promise<void> {\n const dragTracker = await this.#dragTracker();\n dragTracker.addEventListener(\n \"press\",\n (async (e: CustomEvent<PressInfo>) => {\n const movePressInput =\n await this.model!.twistySceneModel.movePressInput.get();\n if (movePressInput !== \"basic\") {\n return;\n }\n this.dispatchEvent(\n new CustomEvent(\"press\", {\n detail: {\n pressInfo: e.detail,\n cameraPromise: this.camera(),\n },\n }),\n );\n }) as any as EventListener, // TODO\n );\n }\n\n #onResizeStaleDropper = new StaleDropper<PerspectiveCamera>();\n\n async clearCanvas(): Promise<void> {\n if (this.rendererIsShared) {\n const canvasInfo = await this.canvasInfo();\n canvasInfo.context.clearRect(\n 0,\n 0,\n canvasInfo.canvas.width,\n canvasInfo.canvas.height,\n );\n } else {\n const renderer = await this.renderer();\n const context = renderer.getContext();\n context.clear(context.COLOR_BUFFER_BIT);\n }\n }\n\n // TODO: Why doesn't this work for the top-right back view height?\n #width: number = 0;\n #height: number = 0;\n async #onResize(): Promise<void> {\n const camera = await this.#onResizeStaleDropper.queue(this.camera());\n\n const w = this.contentWrapper.clientWidth;\n const h = this.contentWrapper.clientHeight;\n this.#width = w;\n this.#height = h;\n const off = 0;\n let yoff = 0;\n let excess = 0;\n if (h > w) {\n excess = h - w;\n yoff = -Math.floor(0.5 * excess);\n }\n camera.aspect = w / h;\n camera.setViewOffset(w, h - excess, off, yoff, w, h);\n camera.updateProjectionMatrix(); // TODO\n\n this.clearCanvas();\n if (this.rendererIsShared) {\n const canvasInfo = await this.canvasInfo();\n\n canvasInfo.canvas.width = w * pixelRatio();\n canvasInfo.canvas.height = h * pixelRatio();\n canvasInfo.canvas.style.width = `${w.toString()}px`;\n canvasInfo.canvas.style.height = `${h.toString()}px`;\n } else {\n const renderer = await this.renderer();\n renderer.setSize(w, h, true);\n }\n\n this.scheduleRender();\n }\n\n #cachedRenderer: Promise<WebGLRenderer> | null = null;\n async renderer(): Promise<WebGLRenderer> {\n if (this.rendererIsShared) {\n throw new Error(\"renderer expected to be shared.\");\n }\n return (this.#cachedRenderer ??= newRenderer());\n }\n\n #cachedCanvas: Promise<{\n canvas: HTMLCanvasElement;\n context: CanvasRenderingContext2D;\n }> | null = null;\n async canvasInfo(): Promise<{\n canvas: HTMLCanvasElement;\n context: CanvasRenderingContext2D;\n }> {\n return (this.#cachedCanvas ??= (async () => {\n let canvas: HTMLCanvasElement;\n if (this.rendererIsShared) {\n canvas = this.addElement(document.createElement(\"canvas\"));\n } else {\n const renderer = await this.renderer();\n canvas = this.addElement(renderer.domElement);\n }\n this.loadingElement?.remove();\n const context = canvas.getContext(\"2d\")!;\n return { canvas, context };\n })());\n }\n\n #cachedDragTracker: Promise<DragTracker> | null = null;\n async #dragTracker(): Promise<DragTracker> {\n return (this.#cachedDragTracker ??= (async () => {\n const dragTracker = new DragTracker((await this.canvasInfo()).canvas);\n this.model?.twistySceneModel.dragInput.addFreshListener(\n (dragInputMode: DragInputMode) => {\n let dragInputEnabled = false;\n switch (dragInputMode) {\n case \"auto\": {\n dragTracker.start();\n dragInputEnabled = true;\n break;\n }\n case \"none\": {\n dragTracker.stop();\n break;\n }\n }\n this.contentWrapper.classList.toggle(\n \"drag-input-enabled\",\n dragInputEnabled,\n );\n },\n );\n return dragTracker;\n })());\n }\n\n #cachedCamera: Promise<PerspectiveCamera> | null = null;\n async camera(): Promise<PerspectiveCamera> {\n return (this.#cachedCamera ??= (async () => {\n const camera = new (await bulk3DCode()).ThreePerspectiveCamera(\n 20,\n 1, // We rely on the resize logic to handle this.\n 0.1,\n 20,\n );\n camera.position.copy(\n new (await bulk3DCode()).ThreeVector3(2, 4, 4).multiplyScalar(\n this.options?.backView ? -1 : 1,\n ),\n );\n camera.lookAt(0, 0, 0);\n // TODO: `TwistyOrbitControls` breaks isolateion\n return camera;\n })());\n }\n\n #cachedOrbitControls: Promise<TwistyOrbitControls> | null = null;\n async orbitControls(): Promise<TwistyOrbitControls> {\n return (this.#cachedOrbitControls ??= (async () => {\n const orbitControls = new TwistyOrbitControls(\n this.model!,\n !!this.options?.backView,\n (await this.canvasInfo()).canvas,\n await this.#dragTracker(),\n );\n\n if (this.model) {\n this.addListener(\n this.model.twistySceneModel.orbitCoordinates,\n async (orbitCoordinates: OrbitCoordinates) => {\n const camera = await this.camera();\n setCameraFromOrbitCoordinates(\n camera,\n orbitCoordinates,\n this.options?.backView,\n );\n // TODO: Wrap in StaleDropper?\n\n this.scheduleRender();\n },\n );\n }\n\n return orbitControls;\n })());\n }\n\n addListener<T>(\n prop: TwistyPropParent<T>,\n listener: (value: T) => void,\n ): void {\n prop.addFreshListener(listener);\n this.#disconnectionFunctions.push(() => {\n prop.removeFreshListener(listener);\n // disconnected = true; // TODO\n });\n }\n\n #disconnectionFunctions: (() => void)[] = [];\n disconnect(): void {\n for (const fn of this.#disconnectionFunctions) {\n fn();\n }\n this.#disconnectionFunctions = []; // TODO: Encapsulate this.\n }\n\n #experimentalNextRenderFinishedCallback: (() => void) | null = null;\n experimentalNextRenderFinishedCallback(callback: () => void): void {\n this.#experimentalNextRenderFinishedCallback = callback;\n }\n\n async render(): Promise<void> {\n if (!this.scene) {\n throw new Error(\"Attempted to render without a scene\");\n }\n\n this.stats?.begin();\n\n const [scene, camera, canvas] = await Promise.all([\n this.scene.scene(),\n this.camera(),\n this.canvasInfo(),\n ]);\n if (this.rendererIsShared) {\n renderPooled(this.#width, this.#height, canvas.canvas, scene, camera);\n } else {\n (await this.renderer()).render(scene, camera);\n }\n\n this.stats?.end();\n this.#experimentalNextRenderFinishedCallback?.();\n this.#experimentalNextRenderFinishedCallback = null;\n }\n\n #scheduler = new RenderScheduler(this.render.bind(this));\n scheduleRender(): void {\n // console.log(\"scheduling\", this);\n this.#scheduler.requestAnimFrame();\n }\n}\n\ncustomElementsShim.define(\"twisty-3d-vantage\", Twisty3DVantage);\n"],
4
+ "sourcesContent": ["export const twistyDebugGlobals: {\n // WARNING: The current shared renderer implementation has performance issues, especially in Safari.\n // Avoid using for players that are likely to have dimensions approaching 1 megapixel or higher.\n // TODO: use a dedicated renderer while fullscreen?\n // - \"auto\": Default heuristics.\n // - \"always\": Force all new (i.e. constructed in the future) renderers to be shared\n // - \"never\": Force all new (i.e. constructed in the future) renderers to be dedicated\n shareAllNewRenderers: \"auto\" | \"always\" | \"never\";\n showRenderStats: boolean;\n} = {\n shareAllNewRenderers: \"auto\",\n showRenderStats: false,\n};\n\nexport function setTwistyDebug(\n options: Partial<typeof twistyDebugGlobals>,\n): void {\n for (const [key, value] of Object.entries(options)) {\n if (key in twistyDebugGlobals) {\n (twistyDebugGlobals as any)[key] = value;\n }\n }\n}\n", "// TODO: Pick a much better name.\nexport class PromiseFreshener<T> {\n #latestAssignedIdx = 0;\n #latestResolvedIdx = 0;\n\n // TODO: reject instead? Drop?\n async queue(\n p: Promise<T>,\n ): Promise<{ fresh: false } | { fresh: true; result: T }> {\n const idx = ++this.#latestAssignedIdx;\n const result = await p;\n if (idx > this.#latestResolvedIdx) {\n this.#latestResolvedIdx = idx;\n return {\n fresh: true,\n result: result,\n };\n } else {\n return { fresh: false };\n }\n }\n}\n\n// This will silenty drop a queued Promise (i.e. not resolve it) if a\n// newer queued one already resolved first. This is useful for classes that want\n// to know the \"latest\" state of something without jumping back to an older\n// value by accident.\n// TODO: Remove this because it's too easy to misuse?\nexport class StaleDropper<T> {\n #latestAssignedIdx = 0;\n #latestResolvedIdx = 0;\n\n queue(p: Promise<T>): Promise<T> {\n // biome-ignore lint/suspicious/noAsyncPromiseExecutor: This is a very rare case where we *do* want to drop a Promise sometimes.\n return new Promise(async (resolve, reject) => {\n try {\n const idx = ++this.#latestAssignedIdx;\n const result = await p;\n if (idx > this.#latestResolvedIdx) {\n this.#latestResolvedIdx = idx;\n resolve(result);\n }\n } catch (e) {\n reject(e);\n }\n });\n }\n}\n", "import type { Tagged } from \"type-fest\";\nimport { from } from \"../../../vendor/mit/p-lazy/p-lazy\";\nimport { StaleDropper } from \"../PromiseFreshener\";\nimport type { UserVisibleErrorTracker } from \"../UserVisibleErrorTracker\";\n\ntype InputRecord = Record<string, any>;\n\nexport type InputProps<T extends InputRecord> = {\n [s in keyof T]: TwistyPropParent<T[s]>;\n};\n\ntype InputPromises<T extends InputRecord> = {\n [s in keyof T]: Promise<T[s]>;\n};\n\ntype Generation = Tagged<number, \"Generation\">;\n\ninterface SourceEventDetail<OutputType> {\n sourceProp: TwistyPropSource<OutputType, any>;\n value: Promise<OutputType>; // TODO: remove?\n generation: Generation;\n}\n\ntype SourceEvent<T> = CustomEvent<SourceEventDetail<T>>;\n\nexport type PromiseOrValue<T> = T | Promise<T>;\n\n// Values of T must be immutable.\nlet globalSourceGeneration: Generation = 0 as Generation; // This is incremented before being used, so 1 will be the first active value.\nexport abstract class TwistyPropParent<T> {\n public abstract get(): Promise<T>;\n\n // Don't overwrite this. Overwrite `canReuseValue` instead.\n public canReuse(v1: T, v2: T): boolean {\n return v1 === v2 || this.canReuseValue(v1, v2);\n }\n\n // Overwrite with a cheap semantic comparison when possible.\n // Note that this is not called if `v1 === v2` (in which case the value is automatically reused).\n protected canReuseValue(_v1: T, _v2: T): boolean {\n return false;\n }\n\n debugGetChildren(): TwistyPropDerived<any, any>[] {\n return Array.from(this.#children.values());\n }\n\n // Propagation\n\n #children: Set<TwistyPropDerived<any, any>> = new Set();\n protected addChild(child: TwistyPropDerived<any, any>): void {\n this.#children.add(child);\n }\n\n protected removeChild(child: TwistyPropDerived<any, any>): void {\n this.#children.delete(child);\n }\n\n protected lastSourceGeneration: number = 0;\n // Synchronously marks all descendants as stale. This doesn't actually\n // literally mark as stale, but it updates the last source generation, which\n // is used to tell if a cahced result is stale.\n protected markStale(sourceEvent: SourceEvent<any>): void {\n if (sourceEvent.detail.generation !== globalSourceGeneration) {\n // The full stale propagation is synchronous, so there should not be a new one yet.\n throw new Error(\"A TwistyProp was marked stale too late!\");\n }\n if (this.lastSourceGeneration === sourceEvent.detail.generation) {\n // Already propagated.\n return;\n }\n this.lastSourceGeneration = sourceEvent.detail.generation;\n for (const child of this.#children) {\n child.markStale(sourceEvent);\n }\n // We schedule sending out events *after* the (synchronous) propagation has happened, in\n // case one of the listeners updates a source again.\n this.#scheduleRawDispatch();\n }\n\n #rawListeners: Set<() => void> = new Set();\n /** @deprecated */\n addRawListener(listener: () => void, options?: { initial: boolean }): void {\n this.#rawListeners.add(listener);\n if (options?.initial) {\n listener(); // TODO: wrap in a try?\n }\n }\n\n /** @deprecated */\n removeRawListener(listener: () => void): void {\n this.#rawListeners.delete(listener);\n }\n\n /** @deprecated */\n #scheduleRawDispatch(): void {\n if (!this.#rawDispatchPending) {\n this.#rawDispatchPending = true;\n setTimeout(() => this.#dispatchRawListeners(), 0);\n }\n }\n\n #rawDispatchPending: boolean = false;\n #dispatchRawListeners(): void {\n if (!this.#rawDispatchPending) {\n throw new Error(\"Invalid dispatch state!\");\n }\n for (const listener of this.#rawListeners) {\n listener(); // TODO: wrap in a try?\n }\n this.#rawDispatchPending = false;\n }\n\n #freshListeners: Map<(value: T) => void, () => void> = new Map();\n // TODO: Pick a better name.\n public addFreshListener(listener: (value: T) => void): void {\n const staleDropper: StaleDropper<T> = new StaleDropper<T>();\n let lastResult: T | null = null;\n const callback = async () => {\n const result = await staleDropper.queue(this.get());\n if (lastResult !== null && this.canReuse(lastResult, result)) {\n return;\n }\n lastResult = result;\n listener(result);\n };\n this.#freshListeners.set(listener, callback);\n this.addRawListener(callback, { initial: true });\n }\n\n public removeFreshListener(listener: (value: T) => void): void {\n this.removeRawListener(this.#freshListeners.get(listener)!); // TODO: throw a custom error?\n this.#freshListeners.delete(listener);\n }\n}\n\nexport abstract class TwistyPropSource<\n OutputType,\n InputType = OutputType,\n> extends TwistyPropParent<OutputType> {\n #value: Promise<OutputType>;\n\n public abstract getDefaultValue(): PromiseOrValue<OutputType>;\n\n constructor(initialValue?: PromiseOrValue<InputType>) {\n super();\n this.#value = from(() => this.getDefaultValue());\n if (initialValue) {\n this.#value = this.deriveFromPromiseOrValue(initialValue, this.#value);\n }\n }\n\n set(input: PromiseOrValue<InputType>): void {\n this.#value = this.deriveFromPromiseOrValue(input, this.#value);\n\n const sourceEventDetail: SourceEventDetail<OutputType> = {\n sourceProp: this,\n value: this.#value,\n generation: ++globalSourceGeneration as Generation,\n };\n this.markStale(\n new CustomEvent<SourceEventDetail<OutputType>>(\"stale\", {\n detail: sourceEventDetail,\n }),\n );\n }\n\n async get(): Promise<OutputType> {\n return this.#value;\n }\n\n protected async deriveFromPromiseOrValue(\n input: PromiseOrValue<InputType>,\n oldValuePromise: Promise<OutputType>,\n ): Promise<OutputType> {\n return this.derive(await input, oldValuePromise);\n }\n\n // TODO: add an indirect layer to cache the derivation?\n protected abstract derive(\n input: InputType,\n oldValuePromise: Promise<OutputType>,\n ): PromiseOrValue<OutputType>;\n}\n\nexport abstract class SimpleTwistyPropSource<\n SimpleType,\n> extends TwistyPropSource<SimpleType> {\n protected override derive(input: SimpleType): PromiseOrValue<SimpleType> {\n return input;\n }\n}\n\n// TODO: Can we support `null` as a valid output value without loosening type\n// safety?\nexport const NO_VALUE = Symbol(\"no value\");\nexport type NoValueType = typeof NO_VALUE;\n\nexport abstract class TwistyPropDerived<\n InputTypes extends InputRecord,\n OutputType,\n> extends TwistyPropParent<OutputType> {\n // cachedInputs:\n #parents: InputProps<InputTypes>;\n\n constructor(\n parents: InputProps<InputTypes>,\n protected userVisibleErrorTracker?: UserVisibleErrorTracker,\n ) {\n super();\n this.#parents = parents;\n for (const parent of Object.values(parents)) {\n (\n parent as TwistyPropDerived<InputProps<InputTypes>, OutputType>\n ).addChild(this);\n }\n }\n\n #cachedLastSuccessfulCalculation: {\n inputs: InputTypes;\n output: Promise<OutputType>;\n generation: number;\n } | null = null;\n\n #cachedLatestGenerationCalculation: {\n output: Promise<OutputType>;\n generation: number;\n } | null = null;\n\n public async get(): Promise<OutputType> {\n const generation = this.lastSourceGeneration;\n\n if (this.#cachedLatestGenerationCalculation?.generation === generation) {\n return this.#cachedLatestGenerationCalculation.output;\n }\n\n const latestGenerationCalculation = {\n generation,\n output: this.#cacheDerive(\n this.#getParents(),\n generation,\n this.#cachedLastSuccessfulCalculation,\n ),\n };\n this.#cachedLatestGenerationCalculation = latestGenerationCalculation;\n\n this.userVisibleErrorTracker?.reset();\n return latestGenerationCalculation.output;\n }\n\n async #getParents(): Promise<InputTypes> {\n const inputValuePromises: InputPromises<InputRecord> = {} as any; // TODO\n for (const [key, parent] of Object.entries(this.#parents)) {\n (inputValuePromises as Record<string, Promise<unknown>>)[key] = (\n parent as TwistyPropParent<unknown>\n ).get();\n }\n\n const inputs: InputTypes = {} as any; // TODO\n for (const key in this.#parents) {\n inputs[key] = (await (\n inputValuePromises as Record<string, Promise<unknown>>\n )[key]) as any;\n }\n return inputs;\n }\n\n async #cacheDerive(\n inputsPromise: PromiseOrValue<InputTypes>,\n generation: number,\n cachedLatestGenerationCalculation: {\n inputs: InputTypes;\n output: Promise<OutputType>;\n generation: number;\n } | null = null,\n ): Promise<OutputType> {\n const inputs = await inputsPromise;\n\n const cache = (output: OutputType): OutputType => {\n this.#cachedLastSuccessfulCalculation = {\n inputs,\n output: Promise.resolve(output),\n generation,\n };\n return output;\n };\n\n if (!cachedLatestGenerationCalculation) {\n return cache(await this.derive(inputs));\n }\n\n const cachedInputs = cachedLatestGenerationCalculation.inputs;\n for (const key in this.#parents) {\n const parent = this.#parents[key];\n if (!parent.canReuse(inputs[key], cachedInputs[key])) {\n return cache(await this.derive(inputs));\n }\n }\n\n return cachedLatestGenerationCalculation.output;\n }\n\n protected abstract derive(input: InputTypes): PromiseOrValue<OutputType>;\n}\n\nexport class FreshListenerManager {\n #disconnectionFunctions: (() => void)[] = [];\n\n addListener<T>(\n prop: TwistyPropParent<T>,\n listener: (value: T) => void,\n ): void {\n let disconnected = false;\n const wrappedListener = (value: T) => {\n if (disconnected) {\n // TODO\n // console.warn(\"Should be disconnected!\");\n return;\n }\n listener(value);\n };\n\n prop.addFreshListener(wrappedListener);\n\n this.#disconnectionFunctions.push(() => {\n prop.removeFreshListener(wrappedListener);\n disconnected = true;\n });\n }\n\n // TODO: Figure out the signature to let us do overloads\n /** @deprecated */\n public addMultiListener3<U, V, W>(\n props: [TwistyPropParent<U>, TwistyPropParent<V>, TwistyPropParent<W>],\n listener: (values: [U, V, W]) => void,\n ): void {\n this.addMultiListener(props as any, listener as any); // TODO\n }\n public addMultiListener<U, V>(\n props: [TwistyPropParent<U>, TwistyPropParent<V>],\n listener: (values: [U, V]) => void,\n ) {\n let disconnected = false;\n\n // We're going to get one initial call per prop. We'll ignore all but one.\n let initialIgnoresLeft = props.length - 1;\n const wrappedListener = async (_: any) => {\n if (initialIgnoresLeft > 0) {\n initialIgnoresLeft--;\n return;\n }\n if (disconnected) {\n // TODO\n // console.warn(\"Should be disconnected!\");\n return;\n }\n // We rely on `TwistyProp` caching to give us the full set of latest\n // values efficiently.\n const promises = (props as TwistyPropParent<any>[]).map((prop) =>\n prop.get(),\n );\n const values = await Promise.all(promises);\n listener(values as any); // TODO: fix up types\n };\n\n for (const prop of props) {\n prop.addFreshListener(wrappedListener);\n }\n\n this.#disconnectionFunctions.push(() => {\n for (const prop of props) {\n prop.removeFreshListener(wrappedListener);\n }\n disconnected = true;\n });\n }\n\n public disconnect(): void {\n for (const disconnectionFunction of this.#disconnectionFunctions) {\n disconnectionFunction();\n }\n }\n}\n", "// Workarounds for `node`.\n// TODO: figure out how to remove this.\n\n// This stub does not need to be callable, just constructable to satisfy the `node` loader.\nclass HTMLElementStub {}\n\nlet HTMLElementShim: typeof HTMLElement;\nif (globalThis.HTMLElement) {\n HTMLElementShim = globalThis.HTMLElement;\n} else {\n HTMLElementShim = HTMLElementStub as any;\n}\n\nexport { HTMLElementShim };\n\nclass CustomElementsStub {\n define(): void {\n // nothing\n }\n}\n\nlet customElementsShim: typeof customElements;\n\nif (globalThis.customElements) {\n customElementsShim = globalThis.customElements;\n} else {\n customElementsShim = new CustomElementsStub() as any;\n}\n\nexport { customElementsShim };\n\nlet cssStyleSheetShim: typeof CSSStyleSheet;\n\nclass CSSStyleSheetStub {\n replaceSync(): void {\n // nothing\n }\n}\n\nif (globalThis.CSSStyleSheet) {\n cssStyleSheetShim = globalThis.CSSStyleSheet;\n} else {\n cssStyleSheetShim = CSSStyleSheetStub as any;\n}\n\nexport { cssStyleSheetShim };\n", "import {\n customElementsShim,\n HTMLElementShim,\n} from \"./node-custom-element-shims\";\n\n// - Wrapped element\n// - Shadow root\n// - Content wrapper\nexport class ManagedCustomElement extends HTMLElementShim {\n public readonly shadow: ShadowRoot; // TODO: hide this\n public readonly contentWrapper: HTMLDivElement; // TODO: can we get rid of this wrapper?\n\n constructor(options?: { mode?: \"open\" | \"closed\" }) {\n super();\n this.shadow = this.attachShadow({ mode: options?.mode ?? \"closed\" });\n\n this.contentWrapper = document.createElement(\"div\");\n this.contentWrapper.classList.add(\"wrapper\");\n this.shadow.appendChild(this.contentWrapper);\n }\n\n // Add the source, if not already added.\n // Returns the existing if it's already on the element.\n protected addCSS(cssSource: CSSStyleSheet): void {\n this.shadow.adoptedStyleSheets.push(cssSource);\n }\n\n protected removeCSS(cssSource: CSSStyleSheet) {\n const cssIndex = this.shadow.adoptedStyleSheets.indexOf(cssSource);\n if (typeof cssIndex !== \"undefined\") {\n this.shadow.adoptedStyleSheets.splice(cssIndex, cssIndex + 1);\n }\n }\n\n public addElement<T extends Node>(element: T): T {\n return this.contentWrapper.appendChild(element);\n }\n\n public prependElement<T extends Node>(element: T): void {\n this.contentWrapper.prepend(element);\n }\n\n public removeElement<T extends Node>(element: T): T {\n return this.contentWrapper.removeChild(element);\n }\n}\n\ncustomElementsShim.define(\n \"twisty-managed-custom-element\",\n ManagedCustomElement,\n);\n", "import type { MillisecondTimestamp } from \"./AnimationTypes\";\n\n// Debounces `requestAnimationFrame()`.\nexport class RenderScheduler {\n private animFrameID: number | null = null;\n private animFrame = this.animFrameWrapper.bind(this);\n constructor(private callback: (timestamp: MillisecondTimestamp) => void) {}\n\n requestIsPending(): boolean {\n return !!this.animFrameID;\n }\n\n requestAnimFrame(): void {\n if (!this.animFrameID) {\n this.animFrameID = requestAnimationFrame(this.animFrame);\n }\n }\n\n cancelAnimFrame(): void {\n if (this.animFrameID) {\n cancelAnimationFrame(this.animFrameID);\n this.animFrameID = 0;\n }\n }\n\n private animFrameWrapper(timestamp: DOMHighResTimeStamp): void {\n this.animFrameID = 0;\n this.callback(timestamp as MillisecondTimestamp);\n }\n}\n\n// An interface for classes to use to expose their scheduling.\nexport interface Schedulable {\n scheduleRender(): void;\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\n// TODO: turn these maps into `Set`s?\nexport const hintFaceletStyles = {\n floating: true, // default\n none: true,\n};\nexport type HintFaceletStyle = keyof typeof hintFaceletStyles;\nexport type HintFaceletStyleWithAuto = HintFaceletStyle | \"auto\";\n\nexport class HintFaceletProp extends SimpleTwistyPropSource<HintFaceletStyleWithAuto> {\n getDefaultValue(): HintFaceletStyleWithAuto {\n return \"auto\";\n }\n}\n", "export const TAU = Math.PI * 2;\nexport const DEGREES_PER_RADIAN = 360 / TAU;\n", "/**\n * @author mrdoob / http://mrdoob.com/\n * ESM conversion by Lucas Garron, 2021-12-21\n */\n\nconst performance:\n | null\n | (Performance & {\n memory?: {\n usedJSHeapSize: number;\n jsHeapSizeLimit: number;\n };\n }) = globalThis.performance;\n\nexport class Stats {\n mode = 0;\n\n dom = document.createElement(\"div\");\n\n constructor() {\n this.dom.style.cssText =\n \"position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000\";\n this.dom.addEventListener(\n \"click\",\n (event) => {\n event.preventDefault();\n this.showPanel(++this.mode % this.dom.children.length);\n },\n false,\n );\n\n this.showPanel(0);\n }\n\n addPanel(panel: StatsPanel): StatsPanel {\n this.dom.appendChild(panel.dom);\n return panel;\n }\n\n showPanel(id: number): void {\n for (let i = 0; i < this.dom.children.length; i++) {\n (this.dom.children[i] as HTMLElement).style.display =\n i === id ? \"block\" : \"none\";\n }\n\n this.mode = id;\n }\n\n beginTime = (performance || Date).now();\n prevTime = this.beginTime;\n frames = 0;\n\n fpsPanel = this.addPanel(new StatsPanel(\"FPS\", \"#0ff\", \"#002\"));\n msPanel = this.addPanel(new StatsPanel(\"MS\", \"#0f0\", \"#020\"));\n memPanel = performance?.memory\n ? this.addPanel(new StatsPanel(\"MB\", \"#f08\", \"#201\"))\n : null;\n REVISION = 16;\n\n begin() {\n this.beginTime = (performance || Date).now();\n }\n\n end() {\n this.frames++;\n\n const time = (performance || Date).now();\n\n this.msPanel.update(time - this.beginTime, 200);\n\n if (time >= this.prevTime + 1000) {\n this.fpsPanel.update((this.frames * 1000) / (time - this.prevTime), 100);\n\n this.prevTime = time;\n this.frames = 0;\n\n if (this.memPanel) {\n const memory = performance!.memory!;\n this.memPanel.update(\n memory.usedJSHeapSize / 1048576,\n memory.jsHeapSizeLimit / 1048576,\n );\n }\n }\n\n return time;\n }\n\n update() {\n this.beginTime = this.end();\n }\n}\n\nconst PR = Math.round(globalThis?.window?.devicePixelRatio ?? 1);\n\nconst WIDTH = 80 * PR;\nconst HEIGHT = 48 * PR;\nconst TEXT_X = 3 * PR;\nconst TEXT_Y = 2 * PR;\nconst GRAPH_X = 3 * PR;\nconst GRAPH_Y = 15 * PR;\nconst GRAPH_WIDTH = 74 * PR;\nconst GRAPH_HEIGHT = 30 * PR;\n\nexport class StatsPanel {\n min = Infinity;\n max = 0;\n dom = document.createElement(\"canvas\");\n context = this.dom.getContext(\"2d\")!;\n constructor(\n private name: string,\n private fg: string,\n private bg: string,\n ) {\n this.dom.width = WIDTH;\n this.dom.height = HEIGHT;\n this.dom.style.cssText = \"width:80px;height:48px\";\n\n this.context.font = `bold ${9 * PR}px Helvetica,Arial,sans-serif`;\n this.context.textBaseline = \"top\";\n\n this.context.fillStyle = bg;\n this.context.fillRect(0, 0, WIDTH, HEIGHT);\n\n this.context.fillStyle = fg;\n this.context.fillText(name, TEXT_X, TEXT_Y);\n this.context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);\n\n this.context.fillStyle = bg;\n this.context.globalAlpha = 0.9;\n this.context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);\n }\n\n update(value: number, maxValue: number) {\n this.min = Math.min(this.min, value);\n this.max = Math.max(this.max, value);\n\n this.context.fillStyle = this.bg;\n this.context.globalAlpha = 1;\n this.context.fillRect(0, 0, WIDTH, GRAPH_Y);\n this.context.fillStyle = this.fg;\n this.context.fillText(\n `${Math.round(value)} ${this.name} (${Math.round(this.min)}-${Math.round(\n this.max,\n )})`,\n TEXT_X,\n TEXT_Y,\n );\n\n this.context.drawImage(\n this.dom,\n GRAPH_X + PR,\n GRAPH_Y,\n GRAPH_WIDTH - PR,\n GRAPH_HEIGHT,\n GRAPH_X,\n GRAPH_Y,\n GRAPH_WIDTH - PR,\n GRAPH_HEIGHT,\n );\n\n this.context.fillRect(\n GRAPH_X + GRAPH_WIDTH - PR,\n GRAPH_Y,\n PR,\n GRAPH_HEIGHT,\n );\n\n this.context.fillStyle = this.bg;\n this.context.globalAlpha = 0.9;\n this.context.fillRect(\n GRAPH_X + GRAPH_WIDTH - PR,\n GRAPH_Y,\n PR,\n Math.round((1 - value / maxValue) * GRAPH_HEIGHT),\n );\n }\n}\n", "// TODO can we remove the cached proxy?\n\n// In theory we can, but we've run into situations where imports are not properly cached.\nlet cachedConstructorProxy: Promise<\n typeof import(\"./dynamic-entries/twisty-dynamic-3d\")\n> | null = null;\n\nexport async function bulk3DCode(): Promise<\n typeof import(\"./dynamic-entries/twisty-dynamic-3d\")\n> {\n return (cachedConstructorProxy ??= import(\n \"./dynamic-entries/twisty-dynamic-3d\"\n ));\n}\n", "let globalPixelRatioOverride: number | null = null;\nexport function setGlobalPixelRatioOverride(override: number | null): void {\n globalPixelRatioOverride = override;\n}\n\n// TODO: Handle if you move across screens?\nexport function pixelRatio(): number {\n return globalPixelRatioOverride ?? (devicePixelRatio || 1);\n}\n", "// export class Drag() {\n\n// }\n\ninterface DragInfo {\n attachedInfo: Record<any, any>;\n hasMoved: boolean;\n lastClientX: number;\n lastClientY: number;\n lastTimeStamp: number;\n}\n\ntype PointerID = number;\n\nexport interface DragMovementInfo {\n attachedInfo: Record<any, any>;\n movementX: number;\n movementY: number;\n elapsedMs: number;\n}\n\nexport interface UpInfo {\n attachedInfo: Record<any, any>;\n}\n\nexport interface PressInfo {\n normalizedX: number;\n normalizedY: number;\n rightClick: boolean;\n keys: {\n // TODO: group these\n altKey: boolean;\n ctrlOrMetaKey: boolean;\n shiftKey: boolean;\n };\n}\n\n// Chrome can report movements as low as `0.0000152587890625` even if the cursor did not move at all. So we need a treshold instead.\nconst MOVEMENT_EPSILON = 0.1; // px\n\nexport class DragTracker extends EventTarget {\n #dragInfoMap: Map<PointerID, DragInfo> = new Map();\n\n constructor(public readonly target: HTMLElement) {\n super();\n }\n\n // Idempotent\n start() {\n this.addTargetListener(\"pointerdown\", this.onPointerDown.bind(this));\n // Prevent right-click on desktop (only tested on macOS Chrome/Safari/Firefox) so we can detect right-click moves.\n // TODO: Can we do this selectively, e.g. only on the puzzle? That way we could allow right-click to download the canvas. Unfortunately, it would probably require a sync calculation.\n this.addTargetListener(\"contextmenu\", (e: MouseEvent) => {\n e.preventDefault();\n });\n // Prevent touch scrolling (preventing default on `pointermove` doesn't work).\n this.addTargetListener(\"touchmove\", (e: PointerEvent) =>\n e.preventDefault(),\n );\n // Prevent zooming on double-tap (iOS).\n // This is because `dblclick` works to zoom in, but does *not* work to zoom out. So the user can get stuck zoomed into the player without a way to zoom out.\n this.addTargetListener(\"dblclick\", (e: MouseEvent) => e.preventDefault());\n }\n\n // Idempotent\n stop(): void {\n for (const [eventType, listener] of this.#targetListeners.entries()) {\n this.target.removeEventListener(\n eventType,\n listener as unknown as EventListener,\n ); // TODO\n }\n this.#targetListeners.clear();\n this.#lazyListenersRegistered = false;\n }\n\n #targetListeners = new Map<\n string,\n ((e: MouseEvent) => any) | ((e: PointerEvent) => any)\n >();\n addTargetListener(\n eventType: string,\n listener: ((e: MouseEvent) => any) | ((e: PointerEvent) => any),\n ) {\n if (!this.#targetListeners.has(eventType)) {\n this.target.addEventListener(\n eventType,\n listener as unknown as EventListener, // TODO\n );\n this.#targetListeners.set(eventType, listener);\n }\n }\n\n // This allows us to avoid getting a callback every time the pointer moves over the canvas, until we have a down event.\n // 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.\n #lazyListenersRegistered: boolean = false;\n #registerLazyListeners(): void {\n if (this.#lazyListenersRegistered) {\n return;\n }\n this.addTargetListener(\"pointermove\", this.onPointerMove.bind(this)); // TODO: only register this after pointer down.\n this.addTargetListener(\"pointerup\", this.onPointerUp.bind(this));\n this.#lazyListenersRegistered = true;\n }\n\n #clear(e: PointerEvent): void {\n this.#dragInfoMap.delete(e.pointerId);\n }\n\n // `null`: means: ignore this result (no movement, or not\n #trackDrag(e: PointerEvent): {\n movementInfo: DragMovementInfo | null;\n hasMoved: boolean;\n } {\n // TODO: Find a way to detect if this is an active press, in a way that works cross-platform.\n // if (e.buttons === 0) {\n // return { movementInfo: null, hasMoved: false };\n // }\n const existing = this.#dragInfoMap.get(e.pointerId);\n if (!existing) {\n return { movementInfo: null, hasMoved: false };\n }\n // We would try to use `e.movementX`/`e.movementY`, except Safari:\n // - Does not have those values on i[Pad]OS.\n // - Will always report `0` for these values on macOS.\n // https://bugs.webkit.org/show_bug.cgi?id=220194\n //\n // The following are all insufficiently powerful for detecting the Safari `0` bug:\n // - `\"movementX\" in e`\n // - `e.movementX !== \"undefined\"`\n // - `e.hasOwnProperty(\"movementX\")`\n\n let movementInfo: DragMovementInfo;\n if ((e.movementX ?? 0) !== 0 || (e.movementY ?? 0) !== 0) {\n // We optimistically try to catch sub-pixel movements in Chrome.\n movementInfo = {\n attachedInfo: existing.attachedInfo,\n movementX: e.movementX,\n movementY: e.movementY,\n elapsedMs: e.timeStamp - existing.lastTimeStamp,\n };\n } else {\n movementInfo = {\n attachedInfo: existing.attachedInfo,\n movementX: e.clientX - existing.lastClientX,\n movementY: e.clientY - existing.lastClientY,\n elapsedMs: e.timeStamp - existing.lastTimeStamp,\n };\n }\n existing.lastClientX = e.clientX;\n existing.lastClientY = e.clientY;\n existing.lastTimeStamp = e.timeStamp;\n if (\n Math.abs(movementInfo.movementX) < MOVEMENT_EPSILON &&\n Math.abs(movementInfo.movementY) < MOVEMENT_EPSILON\n ) {\n return { movementInfo: null, hasMoved: existing.hasMoved };\n } else {\n existing.hasMoved = true;\n return { movementInfo, hasMoved: existing.hasMoved };\n }\n }\n\n private onPointerDown(e: PointerEvent) {\n this.#registerLazyListeners();\n const newDragInfo: DragInfo = {\n attachedInfo: {},\n hasMoved: false,\n lastClientX: e.clientX,\n lastClientY: e.clientY,\n lastTimeStamp: e.timeStamp,\n };\n this.#dragInfoMap.set(e.pointerId, newDragInfo);\n this.target.setPointerCapture(e.pointerId);\n }\n\n private onPointerMove(e: PointerEvent) {\n const movementInfo = this.#trackDrag(e).movementInfo;\n if (movementInfo) {\n e.preventDefault();\n this.dispatchEvent(\n new CustomEvent(\"move\", {\n detail: movementInfo,\n }),\n );\n }\n }\n\n private onPointerUp(e: PointerEvent) {\n const trackDragResult = this.#trackDrag(e);\n const existing = this.#dragInfoMap.get(e.pointerId)!; // TODO\n this.#clear(e);\n this.target.releasePointerCapture(e.pointerId); // TODO: unnecessary?\n let event: CustomEvent;\n if (trackDragResult.hasMoved) {\n // TODO: send proper movement/momentum since last move event.\n event = new CustomEvent<UpInfo>(\"up\", {\n detail: { attachedInfo: existing.attachedInfo },\n });\n } else {\n const { altKey, ctrlKey, metaKey, shiftKey } = e;\n event = new CustomEvent<PressInfo>(\"press\", {\n detail: {\n normalizedX: (e.offsetX / this.target.offsetWidth) * 2 - 1,\n normalizedY: 1 - (e.offsetY / this.target.offsetHeight) * 2,\n rightClick: !!(e.button & 2),\n keys: {\n altKey,\n ctrlOrMetaKey: ctrlKey || metaKey,\n shiftKey,\n },\n },\n });\n }\n this.dispatchEvent(event);\n }\n}\n", "// TODO: https://stackoverflow.com/a/40443642\n\n// let shareAllNewRenderers: boolean = false;\n\n// // WARNING: The current shared renderer implementation is not every efficient.\n// // Avoid using for players that are likely to have dimensions approaching 1 megapixel or higher.\n// // TODO: use a dedicated renderer while fullscreen?\n// export function experimentalSetShareAllNewRenderers(share: boolean): void {\n// shareAllNewRenderers = share;\n// }\n\n// const sharedRenderer: WebGLRenderer | null = null;\n\nimport { bulk3DCode } from \"../../heavy-code-imports/3d\";\nimport type {\n Camera,\n LinearSRGBColorSpace,\n Scene,\n WebGLRenderer,\n} from \"../../heavy-code-imports/three-types\";\nimport { pixelRatio } from \"../canvas\";\n\nconst renderers: Promise<WebGLRenderer>[] = [];\n\n// Render result is guaranteed to be available synchronously at resolution time.\nexport async function rawRenderPooled(\n width: number,\n height: number,\n scene: Scene,\n camera: Camera,\n): Promise<HTMLCanvasElement> {\n // At most one in the pool for now.\n if (renderers.length === 0) {\n renderers.push(newRenderer());\n }\n const renderer = await renderers[0];\n // TODO: scissoring\n renderer.setSize(width, height); // TODO: is it faster if we cache values and only call this when necessary?\n renderer.render(scene, camera);\n\n return renderer.domElement;\n}\n\n// let haveSet = false;\nexport async function renderPooled(\n width: number,\n height: number,\n canvas: HTMLCanvasElement,\n scene: Scene,\n camera: Camera,\n): Promise<void> {\n if (width === 0 || height === 0) {\n return;\n }\n // At most one in the pool for now.\n if (renderers.length === 0) {\n renderers.push(newRenderer());\n }\n\n const rendererCanvas = await rawRenderPooled(width, height, scene, camera);\n\n // TODO: Should we cache this? Seems to take about 0.0001ms to get.\n const context = canvas.getContext(\"2d\")!;\n context.clearRect(0, 0, canvas.width, canvas.height);\n context.drawImage(rendererCanvas, 0, 0);\n}\n\n// Workaround to avoid an import of `three`.\nconst linearSRGBColorSpace =\n \"srgb-linear\" satisfies typeof LinearSRGBColorSpace;\n\nexport async function newRenderer(): Promise<WebGLRenderer> {\n const rendererConstructor = (await bulk3DCode()).ThreeWebGLRenderer;\n const renderer = new rendererConstructor({\n antialias: true,\n alpha: true,\n });\n renderer.outputColorSpace = linearSRGBColorSpace; // TODO(https://github.com/cubing/cubing.js/issues/308): remove this\n renderer.setPixelRatio(pixelRatio());\n return renderer;\n}\n", "// The `position` values are a hack for a bug in Safari where the canvas either\n// grows infinitely, or takes up the full `fr` of any encompassing grid (making\n// the contents of that element e.g. over 100% of its height). `contain:\n// content` is a good fix for this, but there is no indication that Safari will\n// support it soon. https://developer.mozilla.org/en-US/docs/Web/CSS/contain\n\nimport { cssStyleSheetShim } from \"../node-custom-element-shims\";\n\nexport const twisty3DVantageCSS = new cssStyleSheetShim();\ntwisty3DVantageCSS.replaceSync(\n `\n:host {\n width: 384px;\n height: 256px;\n display: grid;\n}\n\n.wrapper {\n width: 100%;\n height: 100%;\n display: grid;\n overflow: hidden;\n place-content: center;\n contain: strict;\n}\n\n.loading {\n width: 4em;\n height: 4em;\n border-radius: 2.5em;\n border: 0.5em solid rgba(0, 0, 0, 0);\n border-top: 0.5em solid rgba(0, 0, 0, 0.7);\n border-right: 0.5em solid rgba(0, 0, 0, 0.7);\n animation: fade-in-delayed 4s, rotate 1s linear infinite;\n}\n\n@keyframes fade-in-delayed {\n 0% { opacity: 0; }\n 25% {opacity: 0; }\n 100% { opacity: 1; }\n}\n\n@keyframes rotate {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n}\n\n/* TODO: This is due to stats hack. Replace with \\`canvas\\`. */\n.wrapper > canvas {\n max-width: 100%;\n max-height: 100%;\n animation: fade-in 0.25s ease-in;\n}\n\n@keyframes fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.wrapper.invisible {\n opacity: 0;\n}\n\n.wrapper.drag-input-enabled > canvas {\n cursor: grab;\n}\n\n.wrapper.drag-input-enabled > canvas:active {\n cursor: grabbing;\n}\n`,\n);\n", "import type { Vector3 } from \"three/src/Three.js\";\nimport { RenderScheduler } from \"../../controllers/RenderScheduler\";\nimport { bulk3DCode } from \"../../heavy-code-imports/3d\";\nimport type { OrbitCoordinates } from \"../../model/props/viewer/OrbitCoordinatesRequestProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport type { DragMovementInfo, DragTracker } from \"./DragTracker\";\nimport { DEGREES_PER_RADIAN } from \"./TAU\";\n\nconst INERTIA_DEFAULT: boolean = true;\n\nconst INERTIA_DURATION_MS = 500;\n// If the first inertial render is this long after the last move, we assume the\n// user has halted the cursor and we consider inertia to have \"timed out\". We\n// never begin animating the inertia.\nconst INERTIA_TIMEOUT_MS = 50;\n\nconst VERTICAL_MOVEMENT_BASE_SCALE = 0.75;\n\n// progress is from 0 to 1.\nfunction momentumScale(progress: number) {\n // This is the exponential curve flipped so that\n // - The slope at progress = 0 is 1 (this corresponds to \"x = 1\" on the normal\n // curve).\n // - The scale exponentially \"decays\" until progress = 1.\n // This means the scale at the end will be about 0.418\n return (Math.exp(1 - progress) - (1 - progress)) / (1 - Math.E) + 1;\n}\n\nclass Inertia {\n private scheduler = new RenderScheduler(this.render.bind(this));\n private lastTimestamp: number;\n constructor(\n private startTimestamp: number,\n private momentumX: number,\n private momentumY: number,\n private callback: (movementX: number, movementY: number) => void,\n ) {\n this.scheduler.requestAnimFrame();\n this.lastTimestamp = startTimestamp;\n }\n\n private render(now: DOMHighResTimeStamp) {\n const progressBefore =\n (this.lastTimestamp - this.startTimestamp) / INERTIA_DURATION_MS;\n const progressAfter = Math.min(\n 1,\n (now - this.startTimestamp) / INERTIA_DURATION_MS,\n );\n\n if (\n progressBefore === 0 &&\n progressAfter > INERTIA_TIMEOUT_MS / INERTIA_DURATION_MS\n ) {\n // The user has already paused for a while. Don't start any inertia.\n return;\n }\n\n const delta = momentumScale(progressAfter) - momentumScale(progressBefore);\n\n // TODO: For now, we only carry horizontal momentum. If this should stay, we\n // can remove the plumbing for the Y dimension.\n this.callback(this.momentumX * delta * 1000, this.momentumY * delta * 1000);\n\n if (progressAfter < 1) {\n this.scheduler.requestAnimFrame();\n }\n this.lastTimestamp = now;\n }\n}\n\nexport async function positionToOrbitCoordinates(\n position: Vector3,\n): Promise<OrbitCoordinates> {\n const spherical = new (await bulk3DCode()).ThreeSpherical();\n spherical.setFromVector3(position);\n return {\n latitude: 90 - spherical.phi * DEGREES_PER_RADIAN,\n longitude: spherical.theta * DEGREES_PER_RADIAN,\n distance: spherical.radius,\n };\n}\n\ninterface TwistyOrbitControlsDragAttachedInfo {\n lastTemperedX: number;\n lastTemperedY: number;\n timestamp: number;\n}\n\n// TODO: change mouse cursor while moving.\nexport class TwistyOrbitControls {\n /** @deprecated */\n experimentalInertia: boolean = INERTIA_DEFAULT;\n private onMovementBound = this.onMovement.bind(this);\n public experimentalHasBeenMoved: boolean = false;\n constructor(\n private model: TwistyPlayerModel,\n private mirror: boolean,\n private canvas: HTMLCanvasElement,\n private dragTracker: DragTracker,\n ) {\n this.dragTracker.addEventListener(\n \"move\",\n this.onMove.bind(this) as any as EventListener, // TODO: https://github.com/microsoft/TypeScript/issues/28357\n );\n this.dragTracker.addEventListener(\n \"up\",\n this.onUp.bind(this) as any as EventListener, // TODO: https://github.com/microsoft/TypeScript/issues/28357\n );\n }\n\n // f is the fraction of the canvas traversed per ms.\n temperMovement(f: number): number {\n // This is scaled to be linear for small values, but to reduce large values\n // by a significant factor.\n return (Math.sign(f) * Math.log(Math.abs(f * 10) + 1)) / 6;\n }\n\n onMove(e: CustomEvent<DragMovementInfo>): void {\n e.detail.attachedInfo ??= {};\n\n const { temperedX, temperedY } = this.onMovement(\n e.detail.movementX,\n e.detail.movementY,\n );\n const attachedInfo = e.detail\n .attachedInfo as TwistyOrbitControlsDragAttachedInfo;\n attachedInfo.lastTemperedX = temperedX * 10;\n attachedInfo.lastTemperedY = temperedY * 10;\n attachedInfo.timestamp = e.timeStamp; // TODO\n }\n\n onMovement(\n movementX: number,\n movementY: number,\n ): {\n temperedX: number;\n temperedY: number;\n } {\n const scale = this.mirror ? -1 : 1;\n\n // TODO: refactor\n const minDim = Math.min(this.canvas.offsetWidth, this.canvas.offsetHeight);\n\n const temperedX = this.temperMovement(movementX / minDim);\n const temperedY = this.temperMovement(\n (movementY / minDim) * VERTICAL_MOVEMENT_BASE_SCALE,\n );\n this.model.twistySceneModel.orbitCoordinatesRequest.set(\n (async () => {\n const prevCoords =\n await this.model.twistySceneModel.orbitCoordinates.get();\n\n const newCoords = {\n latitude:\n prevCoords.latitude + 2 * temperedY * DEGREES_PER_RADIAN * scale,\n longitude: prevCoords.longitude - 2 * temperedX * DEGREES_PER_RADIAN,\n };\n return newCoords;\n })(),\n );\n return { temperedX, temperedY };\n }\n\n onUp(e: CustomEvent<DragMovementInfo>): void {\n e.preventDefault();\n if (\n \"lastTemperedX\" in e.detail.attachedInfo &&\n \"lastTemperedY\" in e.detail.attachedInfo &&\n \"timestamp\" in e.detail.attachedInfo &&\n e.timeStamp - e.detail.attachedInfo[\"timestamp\"] < 60 // TODO\n ) {\n new Inertia(\n e.timeStamp, // TODO\n (e.detail.attachedInfo as TwistyOrbitControlsDragAttachedInfo)\n .lastTemperedX,\n (e.detail.attachedInfo as TwistyOrbitControlsDragAttachedInfo)\n .lastTemperedY,\n this.onMovementBound,\n ); // TODO: cancel inertia\n }\n }\n}\n", "import type { PerspectiveCamera, WebGLRenderer } from \"three/src/Three.js\";\nimport { Stats } from \"../../../vendor/mit/three/examples/jsm/libs/stats.modified.module\";\nimport { RenderScheduler } from \"../../controllers/RenderScheduler\";\nimport { twistyDebugGlobals } from \"../../debug\";\nimport { bulk3DCode } from \"../../heavy-code-imports/3d\";\nimport { StaleDropper } from \"../../model/PromiseFreshener\";\nimport type { DragInputMode } from \"../../model/props/puzzle/state/DragInputProp\";\nimport type { TwistyPropParent } from \"../../model/props/TwistyProp\";\nimport type { OrbitCoordinates } from \"../../model/props/viewer/OrbitCoordinatesRequestProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { pixelRatio } from \"../canvas\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { DragTracker, type PressInfo } from \"./DragTracker\";\nimport { newRenderer, renderPooled } from \"./RendererPool\";\nimport { DEGREES_PER_RADIAN } from \"./TAU\";\nimport type { Twisty3DSceneWrapper } from \"./Twisty3DSceneWrapper\";\nimport { twisty3DVantageCSS } from \"./Twisty3DVantage.css\";\nimport { TwistyOrbitControls } from \"./TwistyOrbitControls\";\n\nexport async function setCameraFromOrbitCoordinates(\n camera: PerspectiveCamera,\n orbitCoordinates: OrbitCoordinates,\n backView: boolean = false,\n): Promise<void> {\n const spherical = new (await bulk3DCode()).ThreeSpherical(\n orbitCoordinates.distance,\n (90 - (backView ? -1 : 1) * orbitCoordinates.latitude) / DEGREES_PER_RADIAN,\n ((backView ? 180 : 0) + orbitCoordinates.longitude) / DEGREES_PER_RADIAN,\n );\n spherical.makeSafe();\n camera.position.setFromSpherical(spherical);\n camera.lookAt(0, 0, 0);\n}\n\nlet dedicatedRenderersSoFar = 0;\nconst DEFAULT_MAX_DEDICATED_RENDERERS = 2; // This allows for a front view and a back view (or two separate front views).\nlet sharingRenderers = false;\nfunction shareRenderer(): boolean {\n if (twistyDebugGlobals.shareAllNewRenderers !== \"auto\") {\n if (!twistyDebugGlobals.shareAllNewRenderers) {\n dedicatedRenderersSoFar++;\n }\n return twistyDebugGlobals.shareAllNewRenderers !== \"never\";\n }\n if (dedicatedRenderersSoFar < DEFAULT_MAX_DEDICATED_RENDERERS) {\n dedicatedRenderersSoFar++;\n return false;\n } else {\n sharingRenderers = true;\n return true;\n }\n}\n\nexport function haveStartedSharingRenderers(): boolean {\n return sharingRenderers;\n}\n\nexport class Twisty3DVantage extends ManagedCustomElement {\n scene: Twisty3DSceneWrapper | null = null;\n\n stats: Stats | null = null;\n\n private rendererIsShared: boolean = shareRenderer();\n\n loadingElement: HTMLDivElement | null = null;\n constructor(\n private model?: TwistyPlayerModel,\n scene?: Twisty3DSceneWrapper,\n private options?: { backView?: boolean },\n ) {\n super();\n this.scene = scene ?? null;\n\n this.loadingElement = this.addElement(document.createElement(\"div\"));\n this.loadingElement.classList.add(\"loading\");\n\n if (twistyDebugGlobals.showRenderStats) {\n this.stats = new Stats();\n this.stats.dom.style.position = \"absolute\";\n this.contentWrapper.appendChild(this.stats.dom);\n }\n }\n\n async connectedCallback(): Promise<void> {\n this.addCSS(twisty3DVantageCSS);\n this.addElement((await this.canvasInfo()).canvas);\n\n this.#onResize();\n const observer = new ResizeObserver(this.#onResize.bind(this));\n observer.observe(this.contentWrapper);\n this.orbitControls(); // Instantiate orbit controls\n this.#setupBasicPresses();\n\n this.scheduleRender();\n }\n\n async #setupBasicPresses(): Promise<void> {\n const dragTracker = await this.#dragTracker();\n dragTracker.addEventListener(\n \"press\",\n (async (e: CustomEvent<PressInfo>) => {\n const movePressInput =\n await this.model!.twistySceneModel.movePressInput.get();\n if (movePressInput !== \"basic\") {\n return;\n }\n this.dispatchEvent(\n new CustomEvent(\"press\", {\n detail: {\n pressInfo: e.detail,\n cameraPromise: this.camera(),\n },\n }),\n );\n }) as any as EventListener, // TODO\n );\n }\n\n #onResizeStaleDropper = new StaleDropper<PerspectiveCamera>();\n\n async clearCanvas(): Promise<void> {\n if (this.rendererIsShared) {\n const canvasInfo = await this.canvasInfo();\n canvasInfo.context.clearRect(\n 0,\n 0,\n canvasInfo.canvas.width,\n canvasInfo.canvas.height,\n );\n } else {\n const renderer = await this.renderer();\n const context = renderer.getContext();\n context.clear(context.COLOR_BUFFER_BIT);\n }\n }\n\n // TODO: Why doesn't this work for the top-right back view height?\n #width: number = 0;\n #height: number = 0;\n async #onResize(): Promise<void> {\n const camera = await this.#onResizeStaleDropper.queue(this.camera());\n\n const w = this.contentWrapper.clientWidth;\n const h = this.contentWrapper.clientHeight;\n this.#width = w;\n this.#height = h;\n const off = 0;\n let yoff = 0;\n let excess = 0;\n if (h > w) {\n excess = h - w;\n yoff = -Math.floor(0.5 * excess);\n }\n camera.aspect = w / h;\n camera.setViewOffset(w, h - excess, off, yoff, w, h);\n camera.updateProjectionMatrix(); // TODO\n\n this.clearCanvas();\n if (this.rendererIsShared) {\n const canvasInfo = await this.canvasInfo();\n\n canvasInfo.canvas.width = w * pixelRatio();\n canvasInfo.canvas.height = h * pixelRatio();\n canvasInfo.canvas.style.width = `${w.toString()}px`;\n canvasInfo.canvas.style.height = `${h.toString()}px`;\n } else {\n const renderer = await this.renderer();\n renderer.setSize(w, h, true);\n }\n\n this.scheduleRender();\n }\n\n #cachedRenderer: Promise<WebGLRenderer> | null = null;\n async renderer(): Promise<WebGLRenderer> {\n if (this.rendererIsShared) {\n throw new Error(\"renderer expected to be shared.\");\n }\n return (this.#cachedRenderer ??= newRenderer());\n }\n\n #cachedCanvas: Promise<{\n canvas: HTMLCanvasElement;\n context: CanvasRenderingContext2D;\n }> | null = null;\n async canvasInfo(): Promise<{\n canvas: HTMLCanvasElement;\n context: CanvasRenderingContext2D;\n }> {\n return (this.#cachedCanvas ??= (async () => {\n let canvas: HTMLCanvasElement;\n if (this.rendererIsShared) {\n canvas = this.addElement(document.createElement(\"canvas\"));\n } else {\n const renderer = await this.renderer();\n canvas = this.addElement(renderer.domElement);\n }\n this.loadingElement?.remove();\n const context = canvas.getContext(\"2d\")!;\n return { canvas, context };\n })());\n }\n\n #cachedDragTracker: Promise<DragTracker> | null = null;\n async #dragTracker(): Promise<DragTracker> {\n return (this.#cachedDragTracker ??= (async () => {\n const dragTracker = new DragTracker((await this.canvasInfo()).canvas);\n this.model?.twistySceneModel.dragInput.addFreshListener(\n (dragInputMode: DragInputMode) => {\n let dragInputEnabled = false;\n switch (dragInputMode) {\n case \"auto\": {\n dragTracker.start();\n dragInputEnabled = true;\n break;\n }\n case \"none\": {\n dragTracker.stop();\n break;\n }\n }\n this.contentWrapper.classList.toggle(\n \"drag-input-enabled\",\n dragInputEnabled,\n );\n },\n );\n return dragTracker;\n })());\n }\n\n #cachedCamera: Promise<PerspectiveCamera> | null = null;\n async camera(): Promise<PerspectiveCamera> {\n return (this.#cachedCamera ??= (async () => {\n const camera = new (await bulk3DCode()).ThreePerspectiveCamera(\n 20,\n 1, // We rely on the resize logic to handle this.\n 0.1,\n 20,\n );\n camera.position.copy(\n new (await bulk3DCode()).ThreeVector3(2, 4, 4).multiplyScalar(\n this.options?.backView ? -1 : 1,\n ),\n );\n camera.lookAt(0, 0, 0);\n // TODO: `TwistyOrbitControls` breaks isolateion\n return camera;\n })());\n }\n\n #cachedOrbitControls: Promise<TwistyOrbitControls> | null = null;\n async orbitControls(): Promise<TwistyOrbitControls> {\n return (this.#cachedOrbitControls ??= (async () => {\n const orbitControls = new TwistyOrbitControls(\n this.model!,\n !!this.options?.backView,\n (await this.canvasInfo()).canvas,\n await this.#dragTracker(),\n );\n\n if (this.model) {\n this.addListener(\n this.model.twistySceneModel.orbitCoordinates,\n async (orbitCoordinates: OrbitCoordinates) => {\n const camera = await this.camera();\n setCameraFromOrbitCoordinates(\n camera,\n orbitCoordinates,\n this.options?.backView,\n );\n // TODO: Wrap in StaleDropper?\n\n this.scheduleRender();\n },\n );\n }\n\n return orbitControls;\n })());\n }\n\n addListener<T>(\n prop: TwistyPropParent<T>,\n listener: (value: T) => void,\n ): void {\n prop.addFreshListener(listener);\n this.#disconnectionFunctions.push(() => {\n prop.removeFreshListener(listener);\n // disconnected = true; // TODO\n });\n }\n\n #disconnectionFunctions: (() => void)[] = [];\n disconnect(): void {\n for (const fn of this.#disconnectionFunctions) {\n fn();\n }\n this.#disconnectionFunctions = []; // TODO: Encapsulate this.\n }\n\n #experimentalNextRenderFinishedCallback: (() => void) | null = null;\n experimentalNextRenderFinishedCallback(callback: () => void): void {\n this.#experimentalNextRenderFinishedCallback = callback;\n }\n\n async render(): Promise<void> {\n if (!this.scene) {\n throw new Error(\"Attempted to render without a scene\");\n }\n\n this.stats?.begin();\n\n const [scene, camera, canvas] = await Promise.all([\n this.scene.scene(),\n this.camera(),\n this.canvasInfo(),\n ]);\n if (this.rendererIsShared) {\n renderPooled(this.#width, this.#height, canvas.canvas, scene, camera);\n } else {\n (await this.renderer()).render(scene, camera);\n }\n\n this.stats?.end();\n this.#experimentalNextRenderFinishedCallback?.();\n this.#experimentalNextRenderFinishedCallback = null;\n }\n\n #scheduler = new RenderScheduler(this.render.bind(this));\n scheduleRender(): void {\n // console.log(\"scheduling\", this);\n this.#scheduler.requestAnimFrame();\n }\n}\n\ncustomElementsShim.define(\"twisty-3d-vantage\", Twisty3DVantage);\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-7GUL3OBQ.js";
4
4
  import {
5
5
  node_adapter_default
6
- } from "./chunk-NX2Q6B7Y.js";
6
+ } from "./chunk-ZKJKRQKY.js";
7
7
  import {
8
8
  Alg
9
9
  } from "./chunk-7D7ZUWUK.js";
@@ -348,4 +348,4 @@ export {
348
348
  solveTwips,
349
349
  setSearchDebug
350
350
  };
351
- //# sourceMappingURL=chunk-RKTO4CAU.js.map
351
+ //# sourceMappingURL=chunk-IHFKNNCV.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  cube3x3x3KPuzzleDefinition
3
- } from "./chunk-RUSWM2KK.js";
3
+ } from "./chunk-QSGI7DXX.js";
4
4
  import {
5
5
  TraversalUp,
6
6
  functionFromTraversal
@@ -270,4 +270,4 @@ export {
270
270
  countLeavesInExpansionForSimultaneousMoveIndexer,
271
271
  countMetricMoves
272
272
  };
273
- //# sourceMappingURL=chunk-BUZPONAW.js.map
273
+ //# sourceMappingURL=chunk-LCJT5ROJ.js.map
@@ -15,10 +15,10 @@ import {
15
15
  experimentalIs2x2x2Solved,
16
16
  from,
17
17
  getCached
18
- } from "./chunk-RUSWM2KK.js";
18
+ } from "./chunk-QSGI7DXX.js";
19
19
  import {
20
20
  KPuzzle
21
- } from "./chunk-PSQEELP4.js";
21
+ } from "./chunk-WAYEJXCG.js";
22
22
  import {
23
23
  Move,
24
24
  Pause
@@ -158,14 +158,14 @@ var cube2x2x2 = {
158
158
  fullName: "2\xD72\xD72 Cube",
159
159
  kpuzzle: getCached(async () => {
160
160
  const kpuzzle = new KPuzzle(
161
- (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).cube2x2x2JSON
161
+ (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).cube2x2x2JSON
162
162
  );
163
163
  kpuzzle.definition.experimentalIsPatternSolved = experimentalIs2x2x2Solved;
164
164
  return kpuzzle;
165
165
  }),
166
- svg: async () => (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).cube2x2x2SVG,
166
+ svg: async () => (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).cube2x2x2SVG,
167
167
  llSVG: getCached(
168
- async () => (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).cube2x2x2LLSVG
168
+ async () => (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).cube2x2x2LLSVG
169
169
  ),
170
170
  pg: getCached(async () => {
171
171
  return asyncGetPuzzleGeometry("2x2x2");
@@ -442,11 +442,11 @@ var clock = {
442
442
  // Patent application year: https://www.jaapsch.net/puzzles/patents/us4869506.pdf
443
443
  kpuzzle: getCached(
444
444
  async () => new KPuzzle(
445
- (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).clockJSON
445
+ (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).clockJSON
446
446
  )
447
447
  ),
448
448
  svg: getCached(async () => {
449
- return (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).clockSVG;
449
+ return (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).clockSVG;
450
450
  })
451
451
  };
452
452
 
@@ -615,11 +615,11 @@ var melindas2x2x2x2 = {
615
615
  // inventionYear: 20__, // TODO
616
616
  kpuzzle: getCached(
617
617
  async () => new KPuzzle(
618
- (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).melindas2x2x2x2OrbitJSON
618
+ (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).melindas2x2x2x2OrbitJSON
619
619
  )
620
620
  ),
621
621
  svg: getCached(async () => {
622
- return (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).melindas2x2x2x2OrbitSVG;
622
+ return (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).melindas2x2x2x2OrbitSVG;
623
623
  })
624
624
  };
625
625
 
@@ -633,7 +633,7 @@ var PyraminxPuzzleLoader = class extends PGPuzzleLoader {
633
633
  });
634
634
  }
635
635
  svg = getCached(async () => {
636
- return (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).pyraminxSVG;
636
+ return (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).pyraminxSVG;
637
637
  });
638
638
  algTransformData = {
639
639
  "\u2194 Mirror (x)": {
@@ -680,11 +680,11 @@ var square1 = {
680
680
  // Czech patent application year: http://spisy.upv.cz/Patents/FullDocuments/277/277266.pdf
681
681
  kpuzzle: getCached(
682
682
  async () => new KPuzzle(
683
- (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).sq1HyperOrbitJSON
683
+ (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).sq1HyperOrbitJSON
684
684
  )
685
685
  ),
686
686
  svg: getCached(async () => {
687
- return (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).sq1HyperOrbitSVG;
687
+ return (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).sq1HyperOrbitSVG;
688
688
  })
689
689
  };
690
690
 
@@ -697,11 +697,11 @@ var tri_quad = {
697
697
  // https://twistypuzzles.com/cgi-bin/puzzle.cgi?pkey=6809
698
698
  kpuzzle: getCached(
699
699
  async () => new KPuzzle(
700
- (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).triQuadJSON
700
+ (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).triQuadJSON
701
701
  )
702
702
  ),
703
703
  svg: getCached(async () => {
704
- return (await import("./puzzles-dynamic-side-events-BOGUHF4Q.js")).triQuadSVG;
704
+ return (await import("./puzzles-dynamic-side-events-IMYJ533P.js")).triQuadSVG;
705
705
  })
706
706
  };
707
707
 
@@ -768,4 +768,4 @@ export {
768
768
  cube2x2x2,
769
769
  puzzles
770
770
  };
771
- //# sourceMappingURL=chunk-WIZJQ7QS.js.map
771
+ //# sourceMappingURL=chunk-MZKROP74.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  KPattern,
3
3
  KPuzzle
4
- } from "./chunk-PSQEELP4.js";
4
+ } from "./chunk-WAYEJXCG.js";
5
5
  import {
6
6
  Alg,
7
7
  Commutator,
@@ -1716,13 +1716,13 @@ var cube3x3x3 = {
1716
1716
  return experimental3x3x3KPuzzle;
1717
1717
  }),
1718
1718
  svg: getCached(async () => {
1719
- return (await import("./puzzles-dynamic-3x3x3-JWIWLLZA.js")).cube3x3x3SVG;
1719
+ return (await import("./puzzles-dynamic-3x3x3-FYXD7SIU.js")).cube3x3x3SVG;
1720
1720
  }),
1721
1721
  llSVG: getCached(async () => {
1722
- return (await import("./puzzles-dynamic-3x3x3-JWIWLLZA.js")).cube3x3x3LLSVG;
1722
+ return (await import("./puzzles-dynamic-3x3x3-FYXD7SIU.js")).cube3x3x3LLSVG;
1723
1723
  }),
1724
1724
  llFaceSVG: getCached(async () => {
1725
- return (await import("./puzzles-dynamic-3x3x3-JWIWLLZA.js")).cube3x3x3LLFaceSVG;
1725
+ return (await import("./puzzles-dynamic-3x3x3-FYXD7SIU.js")).cube3x3x3LLFaceSVG;
1726
1726
  }),
1727
1727
  pg: getCached(async () => {
1728
1728
  return asyncGetPuzzleGeometry("3x3x3");
@@ -1762,4 +1762,4 @@ export {
1762
1762
  PGPuzzleLoader,
1763
1763
  CubePGPuzzleLoader
1764
1764
  };
1765
- //# sourceMappingURL=chunk-RUSWM2KK.js.map
1765
+ //# sourceMappingURL=chunk-QSGI7DXX.js.map