cubing 0.26.2 → 0.26.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/cubing/twisty/controllers/AnimationTypes.ts", "../../../src/cubing/twisty/controllers/RenderScheduler.ts", "../../../src/cubing/twisty/model/helpers.ts", "../../../src/cubing/twisty/controllers/TwistyAnimationController.ts", "../../../src/cubing/twisty/controllers/TwistyPlayerController.ts", "../../../src/cubing/twisty/model/props/viewer/ControlPanelProp.ts", "../../../src/cubing/twisty/views/node-custom-element-shims.ts", "../../../src/cubing/twisty/views/ManagedCustomElement.ts", "../../../src/cubing/twisty/views/TwistyViewerWrapper.css.ts", "../../../src/cubing/twisty/views/2D/Twisty2DPuzzle.css.ts", "../../../src/cubing/twisty/views/2D/KPuzzleSVGWrapper.ts", "../../../src/cubing/twisty/views/2D/Twisty2DPuzzle.ts", "../../../src/cubing/twisty/views/2D/Twisty2DPuzzleWrapper.ts", "../../../src/cubing/twisty/views/2D/Twisty2DSceneWrapper.ts", "../../../src/cubing/twisty/views/ClassListManager.ts", "../../../src/cubing/twisty/views/3D/Twisty3DPuzzleWrapper.ts", "../../../src/cubing/vendor/three/examples/jsm/libs/stats.modified.module.ts", "../../../src/cubing/twisty/views/canvas.ts", "../../../src/cubing/twisty/views/3D/Twisty3DVantage.css.ts", "../../../src/cubing/twisty/views/3D/DragTracker.ts", "../../../src/cubing/twisty/views/3D/RendererPool.ts", "../../../src/cubing/twisty/views/3D/TwistyOrbitControls.ts", "../../../src/cubing/twisty/views/3D/Twisty3DVantage.ts", "../../../src/cubing/twisty/views/3D/Twisty3DSceneWrapper.ts", "../../../src/cubing/twisty/views/control-panel/TwistyButtons.css.ts", "../../../src/cubing/twisty/views/document.ts", "../../../src/cubing/twisty/views/control-panel/webkit-fullscreen.ts", "../../../src/cubing/twisty/model/props/viewer/ButtonAppearanceProp.ts", "../../../src/cubing/twisty/views/control-panel/TwistyButtons.ts", "../../../src/cubing/twisty/views/control-panel/TwistyScrubber.css.ts", "../../../src/cubing/twisty/views/control-panel/TwistyScrubber.ts", "../../../src/cubing/twisty/views/screenshot.ts", "../../../src/cubing/twisty/views/TwistyPlayer.css.ts", "../../../src/cubing/twisty/model/props/general/ArbitraryStringProp.ts", "../../../src/cubing/twisty/model/props/general/URLProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/AlgProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/AlgTransformationProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/AnchorTransformationProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/CatchUpMoveProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/CurrentLeavesSimplified.ts", "../../../src/cubing/twisty/model/props/puzzle/state/CurrentMoveInfoProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/CurrentStateProp.ts", "../../../src/cubing/twisty/controllers/indexer/AlgDuration.ts", "../../../src/cubing/twisty/controllers/indexer/SimpleAlgIndexer.ts", "../../../src/cubing/twisty/controllers/indexer/simultaneous-moves/simul-moves.ts", "../../../src/cubing/twisty/controllers/indexer/simultaneous-moves/SimultaneousMoveIndexer.ts", "../../../src/cubing/twisty/controllers/indexer/tree/AlgWalker.ts", "../../../src/cubing/twisty/controllers/indexer/tree/chunkAlgs.ts", "../../../src/cubing/twisty/controllers/indexer/tree/TreeAlgIndexer.ts", "../../../src/cubing/twisty/model/props/puzzle/state/IndexerConstructorProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/IndexerConstructorRequestProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/IndexerProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/LegacyPositionProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/NaiveMoveCountProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/PuzzleAlgProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/SetupAnchorProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/SetupTransformationProp.ts", "../../../src/cubing/twisty/model/props/puzzle/structure/KPuzzleProp.ts", "../../../src/cubing/twisty/model/props/puzzle/structure/PuzzleDescriptionProp.ts", "../../../src/cubing/twisty/model/props/puzzle/structure/PuzzleIDProp.ts", "../../../src/cubing/twisty/model/props/puzzle/structure/PuzzleIDRequestProp.ts", "../../../src/cubing/twisty/model/props/puzzle/structure/PuzzleLoaderProp.ts", "../../../src/cubing/twisty/model/props/timeline/CoarseTimelineInfoProp.ts", "../../../src/cubing/twisty/model/props/timeline/DetailedTimelineInfoProp.ts", "../../../src/cubing/twisty/model/props/timeline/PlayingInfoProp.ts", "../../../src/cubing/twisty/model/props/timeline/TempoScaleProp.ts", "../../../src/cubing/twisty/model/props/timeline/TimestampRequestProp.ts", "../../../src/cubing/twisty/model/props/viewer/BackViewProp.ts", "../../../src/cubing/twisty/model/props/viewer/TimeRangeProp.ts", "../../../src/cubing/twisty/model/props/viewer/ViewerLinkProp.ts", "../../../src/cubing/twisty/model/props/viewer/VisualizationProp.ts", "../../../src/cubing/twisty/model/props/viewer/VisualizationStrategyProp.ts", "../../../src/cubing/twisty/model/props/puzzle/display/FoundationDisplayProp.ts", "../../../src/cubing/twisty/model/props/puzzle/display/SpriteProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/DragInputProp.ts", "../../../src/cubing/twisty/model/props/puzzle/state/MovePressInputProp.ts", "../../../src/cubing/twisty/model/props/viewer/BackgroundProp.ts", "../../../src/cubing/twisty/model/props/viewer/LatitudeLimit.ts", "../../../src/cubing/twisty/model/props/viewer/OrbitCoordinatesRequestProp.ts", "../../../src/cubing/twisty/model/props/viewer/OrbitCoordinatesProp.ts", "../../../src/cubing/twisty/model/TwistySceneModel.ts", "../../../src/cubing/twisty/model/UserVisibleErrorTracker.ts", "../../../src/cubing/twisty/model/TwistyPlayerModel.ts", "../../../src/cubing/twisty/views/TwistyPlayerSettable.ts", "../../../src/cubing/twisty/views/TwistyPlayer.ts", "../../../src/cubing/twisty/views/TwistyAlgViewer.css.ts", "../../../src/cubing/twisty/views/TwistyAlgViewer.ts", "../../../src/cubing/twisty/views/TwistyAlgEditor/LeafTokens.ts", "../../../src/cubing/twisty/views/TwistyAlgEditor/model.ts", "../../../src/cubing/twisty/views/TwistyAlgEditor/TwistyAlgEditor.css.ts", "../../../src/cubing/twisty/views/TwistyAlgEditor/TwistyAlgEditor.ts", "../../../src/cubing/twisty/views/twizzle/TwizzleLink.css.ts", "../../../src/cubing/twisty/views/twizzle/url-params.ts", "../../../src/cubing/twisty/views/twizzle/TwizzleLink.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Move } from \"../../alg\";\nimport type { KState } from \"../../kpuzzle/KState\";\n\nexport type MillisecondTimestamp = number;\n\n// TODO: unify duration/timstamp types\nexport type Duration = MillisecondTimestamp; // Duration in milliseconds\n// TODO: Extend `number`, introduce MoveSequenceTimestamp vs. EpochTimestamp,\n// force Duration to be a difference.\nexport type Timestamp = MillisecondTimestamp; // Duration since a particular epoch.\n\nexport type Fraction = number; // Value from 0 to 1.\n\n// 1, 0, -1 are used as scalars for `directionScalar` below.\nexport enum Direction {\n Forwards = 1,\n Paused = 0,\n Backwards = -1,\n}\n\nexport function directionScalar(direction: Direction): MillisecondTimestamp {\n return direction;\n}\n\nexport interface MoveInProgress {\n move: Move;\n direction: Direction;\n fraction: number;\n}\n\nexport type PuzzlePosition = {\n state: KState;\n movesInProgress: MoveInProgress[];\n};\n\nexport enum BoundaryType {\n Move = \"move\",\n EntireTimeline = \"entire-timeline\",\n}\n\nexport interface TimeRange {\n start: MillisecondTimestamp;\n end: MillisecondTimestamp;\n}\n\n// export type DurationForAmount = (amount: number) => Duration;\n\nexport interface PositionListener {\n onPositionChange(position: PuzzlePosition): void;\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: DOMHighResTimeStamp) => void) {}\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);\n }\n}\n\n// An interface for classes to use to expose their scheduling.\nexport interface Schedulable {\n scheduleRender(): void;\n}\n", "export function arrayEquals<T>(a: readonly T[], b: readonly T[]): boolean {\n if (a === b) {\n return true;\n }\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n}\n\nexport function arrayEqualsCompare<T>(\n a: readonly T[],\n b: readonly T[],\n compare: (a: T, b: T) => boolean,\n): boolean {\n if (a === b) {\n return true;\n }\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (!compare(a[i], b[i])) {\n return false;\n }\n }\n return true;\n}\n\n// Assumes `offset > 0`. Will produce invalid values if not!\n// We don't check for that, since this can be a hot path.\nexport function mod(v: number, m: number, offset = 0): number {\n return (((v % m) + m + offset) % m) - offset;\n}\n\nexport function modIntoRange(\n v: number,\n rangeMin: number,\n rangeMax: number,\n): number {\n return mod(v - rangeMin, rangeMax - rangeMin) + rangeMin;\n}\n", "import {\n BoundaryType,\n Direction,\n directionScalar,\n MillisecondTimestamp,\n TimeRange,\n} from \"./AnimationTypes\";\nimport { RenderScheduler } from \"./RenderScheduler\";\nimport type {\n PlayingInfo,\n SimpleDirection,\n} from \"../model/props/timeline/PlayingInfoProp\";\nimport type { TwistyPlayerModel } from \"../model/TwistyPlayerModel\";\nimport { StaleDropper } from \"../model/PromiseFreshener\";\nimport type { CurrentMoveInfo } from \"./indexer/AlgIndexer\";\nimport type { TimestampRequest } from \"../model/props/timeline/TimestampRequestProp\";\nimport { modIntoRange } from \"../model/helpers\";\nimport type { CatchUpMove } from \"../model/props/puzzle/state/CatchUpMoveProp\";\n\n// TODO: Figure out a better way for the controller to instruct the player.\nexport interface TwistyAnimationControllerDelegate {\n flash(): void;\n}\n\n// We use a separate helper to separate the anim frame callbacks (and their cancellations).\n// TODO: fold this into the main controller\nclass CatchUpHelper {\n catchingUp: boolean = false;\n pendingFrame = false;\n\n constructor(private model: TwistyPlayerModel) {}\n\n private scheduler: RenderScheduler = new RenderScheduler(\n this.animFrame.bind(this),\n );\n\n start(): void {\n if (!this.catchingUp) {\n this.lastTimestamp = performance.now();\n }\n this.catchingUp = true;\n this.pendingFrame = true;\n this.scheduler.requestAnimFrame();\n }\n\n stop(): void {\n this.catchingUp = false;\n this.scheduler.cancelAnimFrame();\n }\n\n catchUpMs = 500;\n lastTimestamp = 0;\n animFrame(timestamp: MillisecondTimestamp): void {\n this.scheduler.requestAnimFrame();\n const delta = (timestamp - this.lastTimestamp) / this.catchUpMs;\n this.lastTimestamp = timestamp;\n\n this.model.catchUpMove.set(\n (async () => {\n const previousCatchUpMove = await this.model.catchUpMove.get();\n if (previousCatchUpMove.move === null) {\n return previousCatchUpMove;\n }\n\n const amount = previousCatchUpMove.amount + delta; // TODO: use tempo scale?\n if (amount >= 1) {\n this.pendingFrame = true;\n this.stop();\n this.model.timestampRequest.set(\"end\");\n return {\n move: null,\n amount: 0,\n };\n }\n this.pendingFrame = false;\n return {\n move: previousCatchUpMove.move,\n amount: amount,\n };\n })(),\n );\n }\n}\n\n// This controls the logic for animation, so that the main controller can focus on the right API abstractions.\nexport class TwistyAnimationController {\n // TODO: #private?\n private playing: boolean = false;\n private direction: Direction = Direction.Forwards;\n\n private catchUpHelper: CatchUpHelper;\n\n private model: TwistyPlayerModel;\n\n private lastDatestamp: MillisecondTimestamp = 0;\n private lastTimestampPromise: Promise<MillisecondTimestamp>;\n\n private scheduler: RenderScheduler = new RenderScheduler(\n this.animFrame.bind(this),\n );\n\n constructor(\n model: TwistyPlayerModel,\n private delegate: TwistyAnimationControllerDelegate,\n ) {\n this.model = model;\n this.lastTimestampPromise = this.#effectiveTimestampMilliseconds();\n\n this.model.playingInfo.addFreshListener(this.onPlayingProp.bind(this)); // TODO\n\n this.catchUpHelper = new CatchUpHelper(this.model);\n this.model.catchUpMove.addFreshListener(this.onCatchUpMoveProp.bind(this)); // TODO\n }\n\n // TODO: Do we need this?\n async onPlayingProp(playingInfo: PlayingInfo): Promise<void> {\n if (playingInfo.playing !== this.playing) {\n playingInfo.playing ? this.play(playingInfo) : this.pause();\n }\n }\n\n // TODO: Do we need this?\n async onCatchUpMoveProp(catchUpMove: CatchUpMove): Promise<void> {\n const catchingUp = catchUpMove.move !== null;\n if (catchingUp !== this.catchUpHelper.catchingUp) {\n catchingUp ? this.catchUpHelper.start() : this.catchUpHelper.stop();\n }\n this.scheduler.requestAnimFrame();\n }\n\n async #effectiveTimestampMilliseconds(): Promise<MillisecondTimestamp> {\n return (await this.model.detailedTimelineInfo.get()).timestamp;\n }\n\n // TODO: Return the animation we've switched to.\n jumpToStart(options?: { flash: boolean }): void {\n this.model.timestampRequest.set(\"start\");\n this.pause();\n if (options?.flash) {\n this.delegate.flash();\n }\n }\n\n // TODO: Return the animation we've switched to.\n jumpToEnd(options?: { flash: boolean }): void {\n this.model.timestampRequest.set(\"end\");\n this.pause();\n if (options?.flash) {\n this.delegate.flash();\n }\n }\n\n // TODO: Return the playing info we've switched to.\n playPause(): void {\n if (this.playing) {\n this.pause();\n } else {\n this.play(); // TODO: Resume direction and looping behaviour?\n }\n }\n\n // TODO: bundle playing direction, and boundary into `toggle`.\n async play(options?: {\n direction?: SimpleDirection;\n untilBoundary?: BoundaryType;\n autoSkipToOtherEndIfStartingAtBoundary?: boolean; // TODO What's a good short name that doesn't imply a more general looping concept?\n loop?: boolean;\n }): Promise<void> {\n // TODO: We might need to cache all playing info?\n // Or maybe we don't have to worry about short-circuiting, since this is idempotent?\n // if (this.playing) {\n // return;\n // }\n\n const direction = options?.direction ?? Direction.Forwards;\n\n const coarseTimelineInfo = await this.model.coarseTimelineInfo.get(); // TODO: Why do we need to read this if we don't use it?\n if (options?.autoSkipToOtherEndIfStartingAtBoundary ?? true) {\n if (direction === Direction.Forwards && coarseTimelineInfo.atEnd) {\n this.model.timestampRequest.set(\"start\");\n this.delegate.flash();\n }\n if (direction === Direction.Backwards && coarseTimelineInfo.atStart) {\n this.model.timestampRequest.set(\"end\");\n this.delegate.flash();\n }\n }\n this.model.playingInfo.set({\n playing: true,\n direction,\n untilBoundary: options?.untilBoundary ?? BoundaryType.EntireTimeline,\n loop: options?.loop ?? false,\n });\n\n this.playing = true;\n this.lastDatestamp = performance.now(); // TODO: Take from event.\n this.lastTimestampPromise = this.#effectiveTimestampMilliseconds();\n\n // TODO: Save timestamp from model?\n this.scheduler.requestAnimFrame();\n }\n\n pause(): void {\n this.playing = false;\n this.scheduler.cancelAnimFrame();\n this.model.playingInfo.set({\n playing: false,\n untilBoundary: BoundaryType.EntireTimeline,\n });\n }\n\n #animFrameEffectiveTimestampStaleDropper: StaleDropper<\n [PlayingInfo, MillisecondTimestamp, TimeRange, number, CurrentMoveInfo]\n > = new StaleDropper<\n [PlayingInfo, MillisecondTimestamp, TimeRange, number, CurrentMoveInfo]\n >();\n\n async animFrame(frameDatestamp: MillisecondTimestamp): Promise<void> {\n if (this.playing) {\n this.scheduler.requestAnimFrame();\n }\n\n const lastDatestamp = this.lastDatestamp;\n const freshenerResult =\n await this.#animFrameEffectiveTimestampStaleDropper.queue(\n Promise.all([\n this.model.playingInfo.get(),\n this.lastTimestampPromise,\n this.model.timeRange.get(),\n this.model.tempoScale.get(),\n this.model.currentMoveInfo.get(),\n ]),\n );\n\n const [playingInfo, lastTimestamp, timeRange, tempoScale, currentMoveInfo] =\n freshenerResult;\n\n // TODO: Get this without wasting time on the others?\n if (!playingInfo.playing) {\n this.playing = false;\n // TODO: Ideally we'd cancel the anim frame from the top of this method.\n // But `this.scheduler.cancelAnimFrame();` might accidentally cancel a\n // legit freshly scheduled frame. We should modify `RenderScheduler` to\n // either have individually cancellable requests, or to have something\n // like a \"default\" anim frame re-request that can be canceled separately.\n //\n // Note that we can't wait until here to call\n // `this.scheduler.requestAnimFrame();`, because that would slow down the\n // frame rate.\n return;\n }\n\n let end = currentMoveInfo.earliestEnd; // timeRange.end\n if (\n currentMoveInfo.currentMoves.length === 0 ||\n playingInfo.untilBoundary === BoundaryType.EntireTimeline\n ) {\n end = timeRange.end;\n }\n\n let start = currentMoveInfo.latestStart; // timeRange.end\n if (\n currentMoveInfo.currentMoves.length === 0 ||\n playingInfo.untilBoundary === BoundaryType.EntireTimeline\n ) {\n start = timeRange.start;\n }\n // const start = currentMoveInfo.latestStart; // timeRange.start // TODO\n\n let delta =\n (frameDatestamp - lastDatestamp) *\n directionScalar(this.direction) *\n tempoScale;\n delta = Math.max(delta, 1); // TODO: This guards against the timestamp going in the wrong direction by accident. Can we avoid it?\n delta *= playingInfo.direction;\n let newTimestamp = lastTimestamp + delta; // TODO: Pre-emptively clamp.\n let newSmartTimestampRequest: Exclude<TimestampRequest, number> | null =\n null;\n\n if (newTimestamp >= end) {\n if (playingInfo.loop) {\n newTimestamp = modIntoRange(\n newTimestamp,\n timeRange.start,\n timeRange.end,\n );\n } else {\n if (newTimestamp === timeRange.end) {\n newSmartTimestampRequest = \"end\";\n } else {\n newTimestamp = end;\n }\n this.playing = false;\n this.model.playingInfo.set({\n playing: false,\n });\n }\n } else if (newTimestamp <= start) {\n if (playingInfo.loop) {\n newTimestamp = modIntoRange(\n newTimestamp,\n timeRange.start,\n timeRange.end,\n );\n } else {\n if (newTimestamp === timeRange.start) {\n newSmartTimestampRequest = \"start\";\n } else {\n newTimestamp = start;\n }\n this.playing = false;\n this.model.playingInfo.set({\n playing: false,\n });\n }\n }\n this.lastDatestamp = frameDatestamp;\n this.lastTimestampPromise = Promise.resolve(newTimestamp); // TODO: Save this earlier? / Do we need to worry about the effecitve timestamp disagreeing?\n this.model.timestampRequest.set(newSmartTimestampRequest ?? newTimestamp);\n }\n}\n", "import type { TwistyPlayerModel } from \"../model/TwistyPlayerModel\";\nimport {\n TwistyAnimationController,\n TwistyAnimationControllerDelegate,\n} from \"./TwistyAnimationController\";\n\nexport class TwistyPlayerController {\n animationController: TwistyAnimationController;\n\n constructor(\n private model: TwistyPlayerModel,\n delegate: TwistyAnimationControllerDelegate,\n ) {\n this.animationController = new TwistyAnimationController(model, delegate);\n }\n\n jumpToStart(options?: { flash: boolean }): void {\n this.animationController.jumpToStart(options);\n }\n\n jumpToEnd(options?: { flash: boolean }): void {\n this.animationController.jumpToEnd(options);\n }\n\n togglePlay(play?: boolean) {\n if (typeof play === \"undefined\") {\n this.animationController.playPause();\n }\n play ? this.animationController.play() : this.animationController.pause();\n }\n\n public async visitTwizzleLink(): Promise<void> {\n const a = document.createElement(\"a\");\n a.href = await this.model.twizzleLink();\n a.target = \"_blank\";\n a.click();\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nexport const controlsLocations = {\n \"bottom-row\": true, // default\n \"none\": true,\n};\nexport type ControlsLocation = keyof typeof controlsLocations;\nexport type ControlPanelThemeWithAuto = ControlsLocation | \"auto\";\n\nexport class ControlPanelProp extends SimpleTwistyPropSource<ControlPanelThemeWithAuto> {\n getDefaultValue(): ControlPanelThemeWithAuto {\n return \"auto\";\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 = 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 = customElements;\n} else {\n customElementsShim = new CustomElementsStub() as any;\n}\n\nexport { customElementsShim };\n", "import {\n HTMLElementShim,\n customElementsShim,\n} from \"./node-custom-element-shims\";\n\nexport class CSSSource {\n constructor(private sourceText: string) {\n // TODO: Replace with adopted style sheets some day if we can.\n // const blob = new Blob([sourceText], {\n // type: \"text/utf8\",\n // });\n // this.url = URL.createObjectURL(blob);\n }\n\n getAsString(): string {\n return this.sourceText;\n }\n}\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 #cssSourceMap: Map<CSSSource, HTMLStyleElement> = new Map();\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 public addCSS(cssSource: CSSSource): HTMLStyleElement {\n const existing = this.#cssSourceMap.get(cssSource);\n if (existing) {\n return existing;\n }\n\n const cssElem: HTMLStyleElement = document.createElement(\"style\");\n cssElem.textContent = cssSource.getAsString();\n\n this.#cssSourceMap.set(cssSource, cssElem);\n this.shadow.appendChild(cssElem);\n return cssElem;\n }\n\n // Remove the source, if it's currently added.\n public removeCSS(cssSource: CSSSource): void {\n const cssElem = this.#cssSourceMap.get(cssSource);\n if (!cssElem) {\n return;\n }\n this.shadow.removeChild(cssElem);\n this.#cssSourceMap.delete(cssSource);\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 { CSSSource } from \"./ManagedCustomElement\";\n\nexport const twistyViewerWrapperCSS = new CSSSource(`\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}\n\n.wrapper > * {\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n.wrapper.back-view-side-by-side {\n grid-template-columns: 1fr 1fr;\n}\n\n.wrapper.back-view-top-right {\n grid-template-columns: 3fr 1fr;\n grid-template-rows: 1fr 3fr;\n}\n\n.wrapper.back-view-top-right > :nth-child(1) {\n grid-row: 1 / 3;\n grid-column: 1 / 3;\n}\n\n.wrapper.back-view-top-right > :nth-child(2) {\n grid-row: 1 / 2;\n grid-column: 2 / 3;\n}\n`);\n", "import { CSSSource } from \"../ManagedCustomElement\";\n\n// TODO: Can we do this without so much nesting, and styling all the nested elems?\nexport const twisty2DSVGCSS = new CSSSource(`\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}\n\n.svg-wrapper,\ntwisty-2d-svg,\nsvg {\n width: 100%;\n height: 100%;\n display: grid;\n min-height: 0;\n}\n\nsvg {\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", "import type { KPuzzle } from \"../../../kpuzzle\";\nimport type { KState } from \"../../../kpuzzle/KState\";\nimport type {\n FaceletMeshAppearance,\n PuzzleAppearance,\n} from \"../../../puzzles/stickerings/appearance\"; // TODO\nconst xmlns = \"http://www.w3.org/2000/svg\";\n\n// Unique ID mechanism to keep SVG gradient element IDs unique. TODO: Is there\n// something more performant, and that can't be broken by other elements of the\n// page? (And also doesn't break if this library is run in parallel.)\nlet svgCounter = 0;\nfunction nextSVGID(): string {\n svgCounter += 1;\n return \"svg\" + svgCounter.toString();\n}\n\n// TODO: This is hardcoded to 3x3x3 SVGs\nconst colorMaps: Partial<\n Record<FaceletMeshAppearance, Record<string, string>>\n> = {\n dim: {\n \"white\": \"#dddddd\",\n \"orange\": \"#884400\",\n \"limegreen\": \"#008800\",\n \"red\": \"#660000\",\n \"rgb(34, 102, 255)\": \"#000088\", // TODO\n \"yellow\": \"#888800\",\n },\n oriented: {\n \"white\": \"#44ddcc\",\n \"orange\": \"#44ddcc\",\n \"limegreen\": \"#44ddcc\",\n \"red\": \"#44ddcc\",\n \"rgb(34, 102, 255)\": \"#44ddcc\", // TODO\n \"yellow\": \"#44ddcc\",\n },\n ignored: {\n \"white\": \"#444444\",\n \"orange\": \"#444444\",\n \"limegreen\": \"#444444\",\n \"red\": \"#444444\",\n \"rgb(34, 102, 255)\": \"#444444\", // TODO\n \"yellow\": \"#444444\",\n },\n invisible: {\n \"white\": \"#00000000\",\n \"orange\": \"#00000000\",\n \"limegreen\": \"#00000000\",\n \"red\": \"#00000000\",\n \"rgb(34, 102, 255)\": \"#00000000\", // TODO\n \"yellow\": \"#00000000\",\n },\n};\n\nexport class KPuzzleSVGWrapper {\n public element: HTMLElement;\n public gradientDefs: SVGDefsElement;\n private originalColors: { [type: string]: string } = {};\n private gradients: { [type: string]: SVGGradientElement } = {};\n private svgID: string;\n constructor(\n public kpuzzle: KPuzzle,\n svgSource: string,\n experimentalAppearance?: PuzzleAppearance,\n ) {\n if (!svgSource) {\n throw new Error(`No SVG definition for puzzle type: ${kpuzzle.name()}`);\n }\n\n this.svgID = nextSVGID();\n\n this.element = document.createElement(\"div\");\n this.element.classList.add(\"svg-wrapper\");\n // TODO: Sanitization.\n this.element.innerHTML = svgSource;\n\n const svgElem = this.element.querySelector(\"svg\");\n if (!svgElem) {\n throw new Error(\"Could not get SVG element\");\n }\n if (xmlns !== svgElem.namespaceURI) {\n throw new Error(\"Unexpected XML namespace\");\n }\n svgElem.style.maxWidth = \"100%\";\n svgElem.style.maxHeight = \"100%\";\n this.gradientDefs = document.createElementNS(xmlns, \"defs\");\n svgElem.insertBefore(this.gradientDefs, svgElem.firstChild);\n\n for (const orbitName in kpuzzle.definition.orbits) {\n const orbitDefinition = kpuzzle.definition.orbits[orbitName];\n\n for (let idx = 0; idx < orbitDefinition.numPieces; idx++) {\n for (\n let orientation = 0;\n orientation < orbitDefinition.numOrientations;\n orientation++\n ) {\n const id = this.elementID(orbitName, idx, orientation);\n const elem = this.elementByID(id);\n let originalColor: string = elem.style.fill;\n /// TODO: Allow setting appearance dynamically.\n if (experimentalAppearance) {\n (() => {\n // TODO: dedup with Cube3D,,factor out fallback calculations\n const a = experimentalAppearance.orbits;\n if (!a) {\n return;\n }\n const orbitAppearance = a[orbitName];\n if (!orbitAppearance) {\n return;\n }\n const pieceAppearance = orbitAppearance.pieces[idx];\n if (!pieceAppearance) {\n return;\n }\n const faceletAppearance = pieceAppearance.facelets[orientation];\n if (!faceletAppearance) {\n return;\n }\n const appearance =\n typeof faceletAppearance === \"string\"\n ? faceletAppearance\n : faceletAppearance?.appearance;\n const colorMap = colorMaps[appearance];\n if (colorMap) {\n originalColor = colorMap[originalColor];\n }\n })();\n } else {\n originalColor = elem.style.fill;\n }\n this.originalColors[id] = originalColor;\n this.gradients[id] = this.newGradient(id, originalColor);\n this.gradientDefs.appendChild(this.gradients[id]);\n elem.setAttribute(\"style\", `fill: url(#grad-${this.svgID}-${id})`);\n }\n }\n }\n }\n\n public drawState(state: KState, nextState?: KState, fraction?: number): void {\n this.draw(state, nextState, fraction);\n }\n\n // TODO: save definition in the constructor?\n public draw(state: KState, nextState?: KState, fraction?: number): void {\n const transformation = state.experimentalToTransformation();\n const nextTransformation = nextState?.experimentalToTransformation();\n if (!transformation) {\n throw new Error(\"Distinguishable pieces are not handled for SVG yet!\");\n }\n\n for (const orbitName in transformation.kpuzzle.definition.orbits) {\n const orbitDefinition =\n transformation.kpuzzle.definition.orbits[orbitName];\n\n const curTransformationOrbit =\n transformation.transformationData[orbitName];\n const nextTransformationOrbit = nextTransformation\n ? nextTransformation.transformationData[orbitName]\n : null;\n for (let idx = 0; idx < orbitDefinition.numPieces; idx++) {\n for (\n let orientation = 0;\n orientation < orbitDefinition.numOrientations;\n orientation++\n ) {\n const id = this.elementID(orbitName, idx, orientation);\n const fromCur = this.elementID(\n orbitName,\n curTransformationOrbit.permutation[idx],\n (orbitDefinition.numOrientations -\n curTransformationOrbit.orientation[idx] +\n orientation) %\n orbitDefinition.numOrientations,\n );\n let singleColor = false;\n if (nextTransformationOrbit) {\n const fromNext = this.elementID(\n orbitName,\n nextTransformationOrbit.permutation[idx],\n (orbitDefinition.numOrientations -\n nextTransformationOrbit.orientation[idx] +\n orientation) %\n orbitDefinition.numOrientations,\n );\n if (fromCur === fromNext) {\n singleColor = true; // TODO: Avoid redundant work during move.\n }\n fraction = fraction || 0; // TODO Use the type system to tie this to nextState?\n const easedBackwardsPercent =\n 100 * (1 - fraction * fraction * (2 - fraction * fraction)); // TODO: Move easing up the stack.\n this.gradients[id].children[0].setAttribute(\n \"stop-color\",\n this.originalColors[fromCur],\n );\n this.gradients[id].children[1].setAttribute(\n \"stop-color\",\n this.originalColors[fromCur],\n );\n this.gradients[id].children[1].setAttribute(\n \"offset\",\n `${Math.max(easedBackwardsPercent - 5, 0)}%`,\n );\n this.gradients[id].children[2].setAttribute(\n \"offset\",\n `${Math.max(easedBackwardsPercent - 5, 0)}%`,\n );\n this.gradients[id].children[3].setAttribute(\n \"offset\",\n `${easedBackwardsPercent}%`,\n );\n this.gradients[id].children[4].setAttribute(\n \"offset\",\n `${easedBackwardsPercent}%`,\n );\n this.gradients[id].children[4].setAttribute(\n \"stop-color\",\n this.originalColors[fromNext],\n );\n this.gradients[id].children[5].setAttribute(\n \"stop-color\",\n this.originalColors[fromNext],\n );\n } else {\n singleColor = true; // TODO: Avoid redundant work during move.\n }\n if (singleColor) {\n this.gradients[id].children[0].setAttribute(\n \"stop-color\",\n this.originalColors[fromCur],\n );\n this.gradients[id].children[1].setAttribute(\n \"stop-color\",\n this.originalColors[fromCur],\n );\n this.gradients[id].children[1].setAttribute(\"offset\", `100%`);\n this.gradients[id].children[2].setAttribute(\"offset\", `100%`);\n this.gradients[id].children[3].setAttribute(\"offset\", `100%`);\n this.gradients[id].children[4].setAttribute(\"offset\", `100%`);\n }\n // this.gradients[id]\n // this.elementByID(id).style.fill = this.originalColors[from];\n }\n }\n }\n }\n\n private newGradient(id: string, originalColor: string): SVGGradientElement {\n const grad = document.createElementNS(\n xmlns,\n \"radialGradient\",\n ) as SVGGradientElement;\n grad.setAttribute(\"id\", `grad-${this.svgID}-${id}`);\n grad.setAttribute(\"r\", `70.7107%`); // TODO: Adapt to puzzle.\n const stopDefs = [\n { offset: 0, color: originalColor },\n { offset: 0, color: originalColor },\n { offset: 0, color: \"black\" },\n { offset: 0, color: \"black\" },\n { offset: 0, color: originalColor },\n { offset: 100, color: originalColor },\n ];\n for (const stopDef of stopDefs) {\n const stop = document.createElementNS(xmlns, \"stop\");\n stop.setAttribute(\"offset\", `${stopDef.offset}%`);\n stop.setAttribute(\"stop-color\", stopDef.color);\n stop.setAttribute(\"stop-opacity\", \"1\");\n grad.appendChild(stop);\n }\n return grad;\n }\n\n private elementID(\n orbitName: string,\n idx: number,\n orientation: number,\n ): string {\n return orbitName + \"-l\" + idx + \"-o\" + orientation;\n }\n\n private elementByID(id: string): HTMLElement {\n // TODO: Use classes and scope selector to SVG element.\n return this.element.querySelector(\"#\" + id) as HTMLElement;\n }\n}\n", "import type { PuzzleLoader } from \"../../../puzzles/PuzzleLoader\";\nimport type { PuzzleAppearance } from \"../../../puzzles/stickerings/appearance\";\nimport {\n Direction,\n PositionListener,\n PuzzlePosition,\n} from \"../../controllers/AnimationTypes\";\nimport { RenderScheduler } from \"../../controllers/RenderScheduler\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { FreshListenerManager } from \"../../model/props/TwistyProp\";\nimport { twisty2DSVGCSS } from \"./Twisty2DPuzzle.css\";\nimport type { ExperimentalStickering, PuzzleID } from \"../..\";\nimport type { KPuzzle } from \"../../../kpuzzle\";\nimport { KPuzzleSVGWrapper } from \"./KPuzzleSVGWrapper\";\n\nexport interface Twisty2DPuzzleOptions {\n experimentalStickering?: ExperimentalStickering;\n}\n\n// <twisty-2d-svg>\nexport class Twisty2DPuzzle\n extends ManagedCustomElement\n implements PositionListener\n{\n public svg: KPuzzleSVGWrapper;\n private scheduler = new RenderScheduler(this.render.bind(this));\n #cachedPosition: PuzzlePosition | null = null; // TODO: pull when needed.\n constructor(\n private model?: TwistyPlayerModel,\n private kpuzzle?: KPuzzle,\n private svgSource?: string,\n private options?: Twisty2DPuzzleOptions,\n private puzzleLoader?: PuzzleLoader,\n ) {\n super();\n this.addCSS(twisty2DSVGCSS);\n\n this.resetSVG(); // TODO: do this in `connectedCallback()`?\n\n this.#freshListenerManager.addListener(\n this.model!.puzzleID,\n (puzzleID: PuzzleID) => {\n if (puzzleLoader?.id !== puzzleID) {\n this.disconnect();\n }\n },\n );\n\n this.#freshListenerManager.addListener(\n this.model!.legacyPosition,\n this.onPositionChange.bind(this),\n );\n\n if (this.options?.experimentalStickering) {\n this.experimentalSetStickering(this.options.experimentalStickering);\n }\n }\n\n #freshListenerManager = new FreshListenerManager();\n disconnect(): void {\n this.#freshListenerManager.disconnect();\n }\n\n onPositionChange(position: PuzzlePosition): void {\n try {\n if (position.movesInProgress.length > 0) {\n const move = position.movesInProgress[0].move;\n\n let partialMove = move;\n if (position.movesInProgress[0].direction === Direction.Backwards) {\n partialMove = move.invert();\n }\n const newState = position.state.applyMove(partialMove);\n // TODO: move to render()\n this.svg.draw(\n position.state,\n newState,\n position.movesInProgress[0].fraction,\n );\n } else {\n this.svg.draw(position.state);\n this.#cachedPosition = position;\n }\n } catch (e) {\n console.warn(\n \"Bad position (this doesn't necessarily mean something is wrong). Pre-emptively disconnecting:\",\n this.puzzleLoader?.id,\n e,\n );\n this.disconnect();\n }\n }\n\n scheduleRender(): void {\n this.scheduler.requestAnimFrame();\n }\n\n experimentalSetStickering(stickering: ExperimentalStickering): void {\n (async () => {\n if (!this.puzzleLoader?.appearance) {\n return;\n }\n const appearance = await this.puzzleLoader.appearance(stickering);\n this.resetSVG(appearance);\n })();\n }\n\n // TODO: do this without constructing a new SVG.\n private resetSVG(appearance?: PuzzleAppearance): void {\n if (this.svg) {\n this.removeElement(this.svg.element);\n }\n if (!this.kpuzzle) {\n return; // TODO\n }\n this.svg = new KPuzzleSVGWrapper(this.kpuzzle, this.svgSource!, appearance); // TODO\n this.addElement(this.svg.element);\n if (this.#cachedPosition) {\n this.onPositionChange(this.#cachedPosition);\n }\n }\n\n private render(): void {\n /*...*/\n }\n}\n\ncustomElementsShim.define(\"twisty-2d-puzzle\", Twisty2DPuzzle);\n", "import type { PuzzleLoader } from \"../../../puzzles\";\nimport type { ExperimentalStickering } from \"../../../twisty\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { FreshListenerManager } from \"../../model/props/TwistyProp\";\nimport type { Schedulable } from \"../../controllers/RenderScheduler\";\nimport { Twisty2DPuzzle } from \"./Twisty2DPuzzle\";\n\nexport class Twisty2DPuzzleWrapper implements Schedulable {\n constructor(\n private model: TwistyPlayerModel,\n public schedulable: Schedulable,\n private puzzleLoader: PuzzleLoader,\n private effectiveVisualization: \"2D\" | \"experimental-2D-LL\",\n ) {\n this.twisty2DPuzzle(); // Start constructing.\n\n this.#freshListenerManager.addListener(\n this.model.twistySceneModel.stickering,\n async (stickering: ExperimentalStickering) => {\n (await this.twisty2DPuzzle()).experimentalSetStickering(stickering);\n },\n );\n }\n\n #freshListenerManager = new FreshListenerManager();\n disconnect(): void {\n this.#freshListenerManager.disconnect();\n }\n\n // TODO: Hook this up nicely.\n scheduleRender(): void {\n // Nothing\n }\n\n #cachedTwisty2DPuzzle: Promise<Twisty2DPuzzle> | null = null;\n // TODO: Stale dropper?\n async twisty2DPuzzle(): Promise<Twisty2DPuzzle> {\n return (this.#cachedTwisty2DPuzzle ??= (async () => {\n const svgPromise =\n this.effectiveVisualization === \"experimental-2D-LL\"\n ? this.puzzleLoader.llSVG!()\n : this.puzzleLoader.svg();\n return new Twisty2DPuzzle(\n this.model,\n await this.puzzleLoader.kpuzzle(),\n await svgPromise,\n {},\n this.puzzleLoader,\n );\n })());\n }\n}\n", "import type { Scene as ThreeScene } from \"three\";\nimport type { PuzzleLoader } from \"../../../puzzles\";\nimport type { Schedulable } from \"../../controllers/RenderScheduler\";\nimport { THREEJS } from \"../../heavy-code-imports/3d\";\nimport { FreshListenerManager } from \"../../model/props/TwistyProp\";\nimport type { TwistySceneModel } from \"../../model/TwistySceneModel\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { twistyViewerWrapperCSS } from \"../TwistyViewerWrapper.css\";\nimport { Twisty2DPuzzleWrapper } from \"./Twisty2DPuzzleWrapper\";\n\nexport class Twisty2DSceneWrapper\n extends ManagedCustomElement\n implements Schedulable\n{\n #freshListenerManager = new FreshListenerManager();\n disconnect(): void {\n this.#freshListenerManager.disconnect();\n }\n\n constructor(\n public model?: TwistySceneModel,\n private effectiveVisualization?: \"2D\" | \"experimental-2D-LL\",\n ) {\n super();\n }\n\n async connectedCallback(): Promise<void> {\n this.addCSS(twistyViewerWrapperCSS);\n if (this.model) {\n this.#freshListenerManager.addListener(\n this.model.twistyPlayerModel.puzzleLoader,\n this.onPuzzleLoader.bind(this),\n );\n }\n }\n\n #cachedScene: Promise<ThreeScene> | null;\n async scene(): Promise<ThreeScene> {\n return (this.#cachedScene ??= (async () => new (await THREEJS).Scene())());\n }\n\n scheduleRender(): void {\n this.#currentTwisty2DPuzzleWrapper?.scheduleRender();\n }\n\n #currentTwisty2DPuzzleWrapper: Twisty2DPuzzleWrapper | null = null;\n currentTwisty2DPuzzleWrapper(): Twisty2DPuzzleWrapper | null {\n return this.#currentTwisty2DPuzzleWrapper;\n }\n\n // #oldTwisty3DPuzzleWrappers: Twisty3DPuzzleWrapper[] = []; // TODO: Animate these out.\n async setCurrentTwisty2DPuzzleWrapper(\n twisty2DPuzzleWrapper: Twisty2DPuzzleWrapper,\n ): Promise<void> {\n const old = this.#currentTwisty2DPuzzleWrapper;\n this.#currentTwisty2DPuzzleWrapper = twisty2DPuzzleWrapper;\n old?.disconnect(); // TODO: Disconnect properly.\n const twisty2DPuzzlePromise = twisty2DPuzzleWrapper.twisty2DPuzzle();\n this.contentWrapper.textContent = \"\"; // Clear existing ones.\n this.addElement(await twisty2DPuzzlePromise);\n }\n\n async onPuzzleLoader(puzzleLoader: PuzzleLoader): Promise<void> {\n this.#currentTwisty2DPuzzleWrapper?.disconnect();\n const twisty2DPuzzleWrapper = new Twisty2DPuzzleWrapper(\n this.model!.twistyPlayerModel,\n this,\n puzzleLoader,\n this.effectiveVisualization!,\n );\n\n this.setCurrentTwisty2DPuzzleWrapper(twisty2DPuzzleWrapper);\n }\n}\n\ncustomElementsShim.define(\"twisty-2d-scene-wrapper\", Twisty2DSceneWrapper);\n", "import type { ManagedCustomElement } from \"./ManagedCustomElement\";\n\nexport class ClassListManager<SuffixType extends string> {\n #currentClassName: string | null = null;\n // The prefix should ideally end in a dash.\n constructor(\n private elem: ManagedCustomElement,\n private prefix: string,\n private validSuffixes: SuffixType[],\n ) {}\n\n // Does nothing if there was no value.\n clearValue(): void {\n if (this.#currentClassName) {\n this.elem.contentWrapper.classList.remove(this.#currentClassName);\n }\n this.#currentClassName = null; // TODO: add test for this behaviour.\n }\n\n // Returns if the value changed\n setValue(suffix: SuffixType): boolean {\n if (!this.validSuffixes.includes(suffix)) {\n throw new Error(`Invalid suffix: ${suffix}`);\n }\n const newClassName = `${this.prefix}${suffix}`;\n const changed = this.#currentClassName !== newClassName;\n if (changed) {\n this.clearValue();\n this.elem.contentWrapper.classList.add(newClassName);\n this.#currentClassName = newClassName;\n }\n return changed;\n }\n}\n", "import type { Raycaster, Texture as ThreeTexture } from \"three\";\nimport { experimentalCubeAppearance, PuzzleLoader } from \"../../../puzzles\";\nimport type { ExperimentalStickering } from \"../../../twisty\";\nimport { proxy3D } from \"../../heavy-code-imports/3d\";\nimport type { FoundationDisplay } from \"../../model/props/puzzle/display/FoundationDisplayProp\";\nimport type { HintFaceletStyleWithAuto } from \"../../model/props/puzzle/display/HintFaceletProp\";\nimport { FreshListenerManager } from \"../../model/props/TwistyProp\";\nimport type { VisualizationStrategy } from \"../../model/props/viewer/VisualizationStrategyProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport type { PuzzlePosition } from \"../../controllers/AnimationTypes\";\nimport type { Schedulable } from \"../../controllers/RenderScheduler\";\nimport type { Twisty3DPuzzle } from \"./puzzles/Twisty3DPuzzle\";\nimport type { Cube3D } from \"./puzzles/Cube3D\";\nimport type { PG3D } from \"./puzzles/PG3D\";\n\nexport class Twisty3DPuzzleWrapper implements Schedulable {\n constructor(\n private model: TwistyPlayerModel,\n public schedulable: Schedulable,\n private puzzleLoader: PuzzleLoader,\n private visualizationStrategy: VisualizationStrategy,\n ) {\n this.twisty3DPuzzle(); // Start constructing.\n\n // TODO: Hook up listeners before loading the heavy code in the async constructor, so we get any intermediate updates?\n // Repro: Switch to 40x40x40 a fraction of a second before animation finishes. When it's loaded the itmeline is at the end, but the 40x40x40 is rendered with an earlier position.\n\n this.#freshListenerManager.addListener(\n this.model.puzzleLoader,\n (puzzleLoader: PuzzleLoader) => {\n if (this.puzzleLoader.id !== puzzleLoader.id) {\n this.disconnect();\n }\n },\n );\n this.#freshListenerManager.addListener(\n this.model.legacyPosition,\n async (position: PuzzlePosition) => {\n try {\n (await this.twisty3DPuzzle()).onPositionChange(position);\n this.scheduleRender();\n } catch (e) {\n // TODO\n // console.warn(\n // \"Bad position (this doesn't necessarily mean something is wrong). Pre-emptively disconnecting:\",\n // this.puzzleLoader.id,\n // e,\n // );\n this.disconnect();\n }\n },\n );\n\n this.#freshListenerManager.addListener(\n this.model.twistySceneModel.hintFacelet,\n async (hintFaceletStyle: HintFaceletStyleWithAuto) => {\n (\n (await this.twisty3DPuzzle()) as Cube3D | PG3D\n ).experimentalUpdateOptions({\n hintFacelets:\n hintFaceletStyle === \"auto\" ? \"floating\" : hintFaceletStyle,\n });\n this.scheduleRender();\n },\n );\n this.#freshListenerManager.addListener(\n this.model.twistySceneModel.foundationDisplay,\n async (foundationDisplay: FoundationDisplay) => {\n (\n (await this.twisty3DPuzzle()) as Cube3D | PG3D\n ).experimentalUpdateOptions({\n showFoundation: foundationDisplay !== \"none\",\n });\n this.scheduleRender();\n },\n );\n this.#freshListenerManager.addListener(\n this.model.twistySceneModel.stickering,\n async (stickering: ExperimentalStickering) => {\n if (\"setStickering\" in (await this.twisty3DPuzzle())) {\n ((await this.twisty3DPuzzle()) as Cube3D).setStickering(stickering);\n this.scheduleRender();\n } else {\n if (\n [\n \"experimental-global-custom-1\",\n \"experimental-global-custom-2\",\n ].includes(stickering)\n ) {\n const [twisty3D] = await Promise.all([this.twisty3DPuzzle()]);\n (twisty3D as PG3D).experimentalSetAppearance(\n await experimentalCubeAppearance(this.puzzleLoader, stickering),\n );\n this.scheduleRender();\n return;\n }\n\n // TODO: create a prop to handle this.\n if (\"appearance\" in this.puzzleLoader) {\n const [twisty3D, appearancePromise] = await Promise.all([\n this.twisty3DPuzzle(),\n this.puzzleLoader.appearance!(stickering ?? \"full\"),\n ]);\n (twisty3D as PG3D).experimentalSetAppearance(appearancePromise);\n this.scheduleRender();\n }\n }\n },\n );\n\n this.#freshListenerManager.addMultiListener(\n [\n this.model.twistySceneModel.foundationStickerSprite,\n this.model.twistySceneModel.hintStickerSprite,\n ],\n async (\n inputs: [\n foundationSprite: ThreeTexture | null,\n hintSprite: ThreeTexture | null,\n ],\n ) => {\n if (\"experimentalUpdateTexture\" in (await this.twisty3DPuzzle())) {\n ((await this.twisty3DPuzzle()) as PG3D).experimentalUpdateTexture(\n true,\n ...inputs,\n );\n this.scheduleRender();\n }\n },\n );\n }\n\n #freshListenerManager = new FreshListenerManager();\n disconnect(): void {\n this.#freshListenerManager.disconnect();\n }\n\n scheduleRender(): void {\n this.schedulable.scheduleRender();\n }\n\n #cachedTwisty3DPuzzle: Promise<Twisty3DPuzzle> | null = null;\n async twisty3DPuzzle(): Promise<Twisty3DPuzzle> {\n return (this.#cachedTwisty3DPuzzle ??= (async () => {\n const proxyPromise = proxy3D();\n if (\n this.puzzleLoader.id === \"3x3x3\" &&\n this.visualizationStrategy === \"Cube3D\"\n ) {\n // TODO: synchronize\n const [foundationSprite, hintSprite, experimentalStickering] =\n await Promise.all([\n this.model.twistySceneModel.foundationStickerSprite.get(),\n this.model.twistySceneModel.hintStickerSprite.get(),\n this.model.twistySceneModel.stickering.get(),\n ]);\n return (await proxyPromise).cube3DShim({\n foundationSprite,\n hintSprite,\n experimentalStickering,\n });\n } else {\n const [hintFacelets, foundationSprite, hintSprite] = await Promise.all([\n this.model.twistySceneModel.hintFacelet.get(),\n this.model.twistySceneModel.foundationStickerSprite.get(),\n this.model.twistySceneModel.hintStickerSprite.get(),\n ]);\n const pg3d = (await proxyPromise).pg3dShim(\n this.puzzleLoader,\n hintFacelets === \"auto\" ? \"floating\" : hintFacelets,\n );\n // TODO: Figure out how to do this in one place using the listener.\n pg3d.then((p) =>\n p.experimentalUpdateTexture(\n true,\n foundationSprite ?? undefined,\n hintSprite ?? undefined,\n ),\n );\n return pg3d;\n }\n })());\n }\n\n async raycastMove(\n raycasterPromise: Promise<Raycaster>,\n transformations: {\n invert: boolean;\n depth?: \"secondSlice\" | \"rotation\" | \"none\";\n },\n ): Promise<void> {\n const puzzle = (await this.twisty3DPuzzle()) as Cube3D | PG3D;\n // TODO: check this differently.\n if (!(\"experimentalGetControlTargets\" in puzzle)) {\n console.info(\"not PG3D! skipping raycast\");\n return;\n }\n\n const targets = puzzle.experimentalGetControlTargets(); // TODO: sticker targets\n const [raycaster] = await Promise.all([raycasterPromise]);\n\n const intersects = raycaster.intersectObjects(targets);\n if (intersects.length > 0) {\n const closestMove = puzzle.getClosestMoveToAxis(\n intersects[0].point,\n transformations,\n );\n if (closestMove) {\n this.model.experimentalAddMove(closestMove.move, {\n coalesce: true,\n mod: closestMove.order,\n });\n } else {\n console.info(\"Skipping move!\");\n }\n }\n }\n}\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,\n HEIGHT = 48 * PR,\n TEXT_X = 3 * PR,\n TEXT_Y = 2 * PR,\n GRAPH_X = 3 * PR,\n GRAPH_Y = 15 * PR,\n GRAPH_WIDTH = 74 * PR,\n 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(private name: string, private fg: string, private bg: string) {\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) +\n \" \" +\n this.name +\n \" (\" +\n Math.round(this.min) +\n \"-\" +\n Math.round(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", "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", "import { CSSSource } from \"../ManagedCustomElement\";\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\nexport const twisty3DVantageCSS = new CSSSource(`\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 cursor: grab;\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 > canvas:active {\n cursor: grabbing;\n}\n\n.wrapper.invisible {\n opacity: 0;\n}\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 insteadl.\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) => {\n e.preventDefault();\n });\n // Prevent touch scrolling (preventing default on `pointermove` doesn't work).\n this.addTargetListener(\"touchmove\", (e) => e.preventDefault());\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) => e.preventDefault());\n }\n\n // Idempotent\n stop(): void {\n for (const [eventType, listener] of this.#targetListeners.entries()) {\n this.target.removeEventListener(eventType, listener);\n }\n this.#targetListeners.clear();\n }\n\n #targetListeners = new Map<string, (e: MouseEvent) => any>();\n addTargetListener(eventType: string, listener: (e: MouseEvent) => any) {\n if (!this.#targetListeners.has(eventType)) {\n this.target.addEventListener(eventType, listener);\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 { THREEJS } from \"../../heavy-code-imports/3d\";\nimport type { Camera, Scene, WebGLRenderer } from \"three\";\nimport { pixelRatio } from \"../canvas\";\n\nconst renderers: Promise<WebGLRenderer>[] = [];\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 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 // 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(renderer.domElement, 0, 0);\n}\n\nexport async function newRenderer(): Promise<WebGLRenderer> {\n const rendererConstructor = (await THREEJS).WebGLRenderer;\n const renderer = new rendererConstructor({\n antialias: true,\n alpha: true,\n });\n renderer.setPixelRatio(pixelRatio());\n return renderer;\n}\n", "import type { Vector3 } from \"three\";\nimport { RenderScheduler } from \"../../controllers/RenderScheduler\";\nimport { THREEJS } 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 THREEJS).Spherical();\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(\"move\", this.onMove.bind(this));\n this.dragTracker.addEventListener(\"up\", this.onUp.bind(this));\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 (\n e.detail.attachedInfo as TwistyOrbitControlsDragAttachedInfo\n ).lastTemperedX,\n (\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\";\nimport { Stats } from \"../../../vendor/three/examples/jsm/libs/stats.modified.module\";\nimport { THREEJS } from \"../../heavy-code-imports/3d\";\nimport { StaleDropper } from \"../../model/PromiseFreshener\";\nimport type { TwistyPropParent } from \"../../model/props/TwistyProp\";\nimport type { OrbitCoordinates } from \"../../model/props/viewer/OrbitCoordinatesRequestProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { RenderScheduler } from \"../../controllers/RenderScheduler\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { pixelRatio } from \"../canvas\";\nimport { twisty3DVantageCSS } from \"./Twisty3DVantage.css\";\nimport { DragTracker, PressInfo } from \"./DragTracker\";\nimport { newRenderer, renderPooled } from \"./RendererPool\";\nimport { DEGREES_PER_RADIAN } from \"./TAU\";\nimport type { Twisty3DSceneWrapper } from \"./Twisty3DSceneWrapper\";\nimport { TwistyOrbitControls } from \"./TwistyOrbitControls\";\nimport type { DragInputMode } from \"../../model/props/puzzle/state/DragInputProp\";\n\nlet SHOW_STATS = false;\nexport function debugShowRenderStats(enable: boolean): void {\n SHOW_STATS = enable;\n}\n\nexport async function setCameraFromOrbitCoordinates(\n camera: PerspectiveCamera,\n orbitCoordinates: OrbitCoordinates,\n backView: boolean = false,\n): Promise<void> {\n const spherical = new (await THREEJS).Spherical(\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 shareAllNewRenderers: boolean | null = null;\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// - true: Force all new (i.e. constructed in the future) renderers to be shared\n// - false: Force all new (i.e. constructed in the future) renderers to be dedicated\n// - null: Reset to the default heuristics.\nexport function experimentalForceNewRendererSharing(\n share: boolean | null,\n): void {\n shareAllNewRenderers = share;\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).\nfunction shareRenderer(): boolean {\n if (shareAllNewRenderers !== null) {\n if (!shareAllNewRenderers) {\n dedicatedRenderersSoFar++;\n }\n return shareAllNewRenderers;\n }\n if (dedicatedRenderersSoFar < DEFAULT_MAX_DEDICATED_RENDERERS) {\n dedicatedRenderersSoFar++;\n return false;\n } else {\n return true;\n }\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 (SHOW_STATS) {\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(\"press\", 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 });\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();\n canvasInfo.canvas.style.height = h.toString();\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 switch (dragInputMode) {\n case \"auto\":\n dragTracker.start();\n break;\n case \"none\":\n dragTracker.stop();\n break;\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 THREEJS).PerspectiveCamera(\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 THREEJS).Vector3(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 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 }\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", "import type { PerspectiveCamera, Scene as ThreeScene } from \"three\";\nimport type { PuzzleLoader } from \"../../../puzzles\";\nimport type { Schedulable } from \"../../controllers/RenderScheduler\";\nimport { THREEJS } from \"../../heavy-code-imports/3d\";\nimport { StaleDropper } from \"../../model/PromiseFreshener\";\nimport { FreshListenerManager } from \"../../model/props/TwistyProp\";\nimport type {\n BackViewLayout,\n BackViewLayoutWithAuto,\n} from \"../../model/props/viewer/BackViewProp\";\nimport type { VisualizationStrategy } from \"../../model/props/viewer/VisualizationStrategyProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { ClassListManager } from \"../ClassListManager\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { twistyViewerWrapperCSS } from \"../TwistyViewerWrapper.css\";\nimport type { PressInfo } from \"./DragTracker\";\nimport { Twisty3DPuzzleWrapper } from \"./Twisty3DPuzzleWrapper\";\nimport { Twisty3DVantage } from \"./Twisty3DVantage\";\n\nexport class Twisty3DSceneWrapper\n extends ManagedCustomElement\n implements Schedulable\n{\n #backViewClassListManager: ClassListManager<BackViewLayoutWithAuto> =\n new ClassListManager(this, \"back-view-\", [\n \"auto\",\n \"none\",\n \"side-by-side\",\n \"top-right\",\n ]);\n\n #freshListenerManager = new FreshListenerManager();\n disconnect(): void {\n this.#freshListenerManager.disconnect();\n }\n\n constructor(public model?: TwistyPlayerModel) {\n super();\n }\n\n async connectedCallback(): Promise<void> {\n this.addCSS(twistyViewerWrapperCSS);\n const vantage = new Twisty3DVantage(this.model, this);\n this.addVantage(vantage);\n if (this.model) {\n this.#freshListenerManager.addMultiListener(\n [this.model.puzzleLoader, this.model.visualizationStrategy],\n this.onPuzzle.bind(this),\n );\n this.#freshListenerManager.addListener(\n this.model.backView,\n this.onBackView.bind(this),\n );\n }\n this.scheduleRender();\n }\n\n #backViewVantage: Twisty3DVantage | null = null;\n setBackView(backView: BackViewLayout): void {\n const shouldHaveBackView = [\"side-by-side\", \"top-right\"].includes(backView);\n const hasBackView = this.#backViewVantage !== null;\n\n this.#backViewClassListManager.setValue(backView);\n if (shouldHaveBackView) {\n if (!hasBackView) {\n this.#backViewVantage = new Twisty3DVantage(this.model, this, {\n backView: true,\n });\n this.addVantage(this.#backViewVantage);\n this.scheduleRender();\n }\n } else {\n if (this.#backViewVantage) {\n this.removeVantage(this.#backViewVantage);\n this.#backViewVantage = null;\n }\n }\n }\n\n onBackView(backView: BackViewLayout): void {\n this.setBackView(backView);\n }\n\n async onPress(\n e: CustomEvent<{\n pressInfo: PressInfo;\n cameraPromise: Promise<PerspectiveCamera>;\n }>,\n ): Promise<void> {\n const twisty3DPuzzleWrapper = this.#currentTwisty3DPuzzleWrapper;\n if (!twisty3DPuzzleWrapper) {\n console.info(\"no wrapper; skipping scene wrapper press!\");\n return;\n }\n\n const raycasterPromise = (async () => {\n const [camera, three] = await Promise.all([\n e.detail.cameraPromise,\n THREEJS,\n ]);\n\n const raycaster = new three.Raycaster();\n const mouse = new (await THREEJS).Vector2(\n e.detail.pressInfo.normalizedX,\n e.detail.pressInfo.normalizedY,\n );\n raycaster.setFromCamera(mouse, camera);\n return raycaster;\n })();\n\n twisty3DPuzzleWrapper.raycastMove(raycasterPromise, {\n invert: !e.detail.pressInfo.rightClick,\n depth: e.detail.pressInfo.keys.ctrlOrMetaKey\n ? \"rotation\"\n : e.detail.pressInfo.keys.shiftKey\n ? \"secondSlice\"\n : \"none\",\n });\n }\n\n #cachedScene: Promise<ThreeScene> | null;\n async scene(): Promise<ThreeScene> {\n return (this.#cachedScene ??= (async () => new (await THREEJS).Scene())());\n }\n\n #vantages: Set<Twisty3DVantage> = new Set();\n addVantage(vantage: Twisty3DVantage) {\n vantage.addEventListener(\"press\", this.onPress.bind(this));\n this.#vantages.add(vantage);\n this.contentWrapper.appendChild(vantage);\n }\n\n removeVantage(vantage: Twisty3DVantage) {\n this.#vantages.delete(vantage);\n vantage.remove();\n vantage.disconnect();\n this.#currentTwisty3DPuzzleWrapper?.disconnect();\n }\n\n experimentalVantages(): Iterable<Twisty3DVantage> {\n return this.#vantages.values();\n }\n\n scheduleRender(): void {\n for (const vantage of this.#vantages) {\n vantage.scheduleRender();\n }\n }\n\n #currentTwisty3DPuzzleWrapper: Twisty3DPuzzleWrapper | null = null;\n // #oldTwisty3DPuzzleWrappers: Twisty3DPuzzleWrapper[] = []; // TODO: Animate these out.\n async setCurrentTwisty3DPuzzleWrapper(\n scene: ThreeScene,\n twisty3DPuzzleWrapper: Twisty3DPuzzleWrapper,\n ): Promise<void> {\n const old = this.#currentTwisty3DPuzzleWrapper;\n try {\n this.#currentTwisty3DPuzzleWrapper = twisty3DPuzzleWrapper;\n old?.disconnect();\n scene.add(await twisty3DPuzzleWrapper.twisty3DPuzzle());\n } finally {\n if (old) {\n // We wait for the new puzzle to be in place before removing the old one.\n scene.remove(await old.twisty3DPuzzle());\n }\n }\n }\n\n #twisty3DStaleDropper: StaleDropper<[ThreeScene, Twisty3DPuzzleWrapper]> =\n new StaleDropper<[ThreeScene, Twisty3DPuzzleWrapper]>();\n\n async onPuzzle(\n inputs: [\n puzzleLoader: PuzzleLoader,\n visualizationStrategy: VisualizationStrategy,\n ],\n ): Promise<void> {\n if (inputs[1] === \"2D\") {\n // We are being asked to render with stale info. Ignore.\n return;\n }\n this.#currentTwisty3DPuzzleWrapper?.disconnect();\n const [scene, twisty3DPuzzleWrapper] =\n await this.#twisty3DStaleDropper.queue(\n Promise.all([\n this.scene(),\n new Twisty3DPuzzleWrapper(this.model!, this, inputs[0], inputs[1]), // TODO\n ]),\n );\n\n this.setCurrentTwisty3DPuzzleWrapper(scene, twisty3DPuzzleWrapper);\n }\n}\n\ncustomElementsShim.define(\"twisty-3d-scene-wrapper\", Twisty3DSceneWrapper);\n", "import { CSSSource } from \"../ManagedCustomElement\";\n\nexport const buttonGridCSS = new CSSSource(`\n:host {\n width: 384px;\n height: 24px;\n display: grid;\n}\n\n.wrapper {\n width: 100%;\n height: 100%;\n display: grid;\n overflow: hidden;\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n}\n\n.wrapper {\n grid-auto-flow: column;\n}\n\n.viewer-link-none .twizzle-link-button {\n display: none;\n}\n\n.wrapper twisty-button,\n.wrapper twisty-control-button {\n width: inherit;\n height: inherit;\n}\n`);\n\nexport const buttonCSS = new CSSSource(`\n:host:not([hidden]) {\n display: grid;\n}\n\n:host {\n width: 48px;\n height: 24px;\n}\n\n.wrapper {\n width: 100%;\n height: 100%;\n}\n\nbutton {\n width: 100%;\n height: 100%;\n border: none;\n \n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n\n background-color: rgba(196, 196, 196, 0.75);\n}\n\nbutton:enabled {\n background-color: rgba(196, 196, 196, 0.75)\n}\n\nbutton:disabled {\n background-color: rgba(0, 0, 0, 0.4);\n opacity: 0.25;\n pointer-events: none;\n}\n\nbutton:enabled:hover {\n background-color: rgba(255, 255, 255, 0.75);\n box-shadow: 0 0 1em rgba(0, 0, 0, 0.25);\n cursor: pointer;\n}\n\n/* TODO: fullscreen icons have too much padding?? */\n.svg-skip-to-start button,\nbutton.svg-skip-to-start {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik0yNjQzIDEwMzdxMTktMTkgMzItMTN0MTMgMzJ2MTQ3MnEwIDI2LTEzIDMydC0zMi0xM2wtNzEwLTcxMHEtOS05LTEzLTE5djcxMHEwIDI2LTEzIDMydC0zMi0xM2wtNzEwLTcxMHEtOS05LTEzLTE5djY3OHEwIDI2LTE5IDQ1dC00NSAxOUg5NjBxLTI2IDAtNDUtMTl0LTE5LTQ1VjEwODhxMC0yNiAxOS00NXQ0NS0xOWgxMjhxMjYgMCA0NSAxOXQxOSA0NXY2NzhxNC0xMSAxMy0xOWw3MTAtNzEwcTE5LTE5IDMyLTEzdDEzIDMydjcxMHE0LTExIDEzLTE5eiIvPjwvc3ZnPg==\");\n}\n\n.svg-skip-to-end button,\nbutton.svg-skip-to-end {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik05NDEgMjU0N3EtMTkgMTktMzIgMTN0LTEzLTMyVjEwNTZxMC0yNiAxMy0zMnQzMiAxM2w3MTAgNzEwcTggOCAxMyAxOXYtNzEwcTAtMjYgMTMtMzJ0MzIgMTNsNzEwIDcxMHE4IDggMTMgMTl2LTY3OHEwLTI2IDE5LTQ1dDQ1LTE5aDEyOHEyNiAwIDQ1IDE5dDE5IDQ1djE0MDhxMCAyNi0xOSA0NXQtNDUgMTloLTEyOHEtMjYgMC00NS0xOXQtMTktNDV2LTY3OHEtNSAxMC0xMyAxOWwtNzEwIDcxMHEtMTkgMTktMzIgMTN0LTEzLTMydi03MTBxLTUgMTAtMTMgMTl6Ii8+PC9zdmc+\");\n}\n\n.svg-step-forward button,\nbutton.svg-step-forward {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik0yNjg4IDE1NjhxMCAyNi0xOSA0NWwtNTEyIDUxMnEtMTkgMTktNDUgMTl0LTQ1LTE5cS0xOS0xOS0xOS00NXYtMjU2aC0yMjRxLTk4IDAtMTc1LjUgNnQtMTU0IDIxLjVxLTc2LjUgMTUuNS0xMzMgNDIuNXQtMTA1LjUgNjkuNXEtNDkgNDIuNS04MCAxMDF0LTQ4LjUgMTM4LjVxLTE3LjUgODAtMTcuNSAxODEgMCA1NSA1IDEyMyAwIDYgMi41IDIzLjV0Mi41IDI2LjVxMCAxNS04LjUgMjV0LTIzLjUgMTBxLTE2IDAtMjgtMTctNy05LTEzLTIydC0xMy41LTMwcS03LjUtMTctMTAuNS0yNC0xMjctMjg1LTEyNy00NTEgMC0xOTkgNTMtMzMzIDE2Mi00MDMgODc1LTQwM2gyMjR2LTI1NnEwLTI2IDE5LTQ1dDQ1LTE5cTI2IDAgNDUgMTlsNTEyIDUxMnExOSAxOSAxOSA0NXoiLz48L3N2Zz4=\");\n}\n\n.svg-step-backward button,\nbutton.svg-step-backward {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik0yNjg4IDIwNDhxMCAxNjYtMTI3IDQ1MS0zIDctMTAuNSAyNHQtMTMuNSAzMHEtNiAxMy0xMyAyMi0xMiAxNy0yOCAxNy0xNSAwLTIzLjUtMTB0LTguNS0yNXEwLTkgMi41LTI2LjV0Mi41LTIzLjVxNS02OCA1LTEyMyAwLTEwMS0xNy41LTE4MXQtNDguNS0xMzguNXEtMzEtNTguNS04MC0xMDF0LTEwNS41LTY5LjVxLTU2LjUtMjctMTMzLTQyLjV0LTE1NC0yMS41cS03Ny41LTYtMTc1LjUtNmgtMjI0djI1NnEwIDI2LTE5IDQ1dC00NSAxOXEtMjYgMC00NS0xOWwtNTEyLTUxMnEtMTktMTktMTktNDV0MTktNDVsNTEyLTUxMnExOS0xOSA0NS0xOXQ0NSAxOXExOSAxOSAxOSA0NXYyNTZoMjI0cTcxMyAwIDg3NSA0MDMgNTMgMTM0IDUzIDMzM3oiLz48L3N2Zz4=\");\n}\n\n.svg-pause button,\nbutton.svg-pause {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik0yNTYwIDEwODh2MTQwOHEwIDI2LTE5IDQ1dC00NSAxOWgtNTEycS0yNiAwLTQ1LTE5dC0xOS00NVYxMDg4cTAtMjYgMTktNDV0NDUtMTloNTEycTI2IDAgNDUgMTl0MTkgNDV6bS04OTYgMHYxNDA4cTAgMjYtMTkgNDV0LTQ1IDE5aC01MTJxLTI2IDAtNDUtMTl0LTE5LTQ1VjEwODhxMC0yNiAxOS00NXQ0NS0xOWg1MTJxMjYgMCA0NSAxOXQxOSA0NXoiLz48L3N2Zz4=\");\n}\n\n.svg-play button,\nbutton.svg-play {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik0yNDcyLjUgMTgyM2wtMTMyOCA3MzhxLTIzIDEzLTM5LjUgM3QtMTYuNS0zNlYxMDU2cTAtMjYgMTYuNS0zNnQzOS41IDNsMTMyOCA3MzhxMjMgMTMgMjMgMzF0LTIzIDMxeiIvPjwvc3ZnPg==\");\n}\n\n.svg-enter-fullscreen button,\nbutton.svg-enter-fullscreen {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAyOCAyOCIgd2lkdGg9IjI4Ij48cGF0aCBkPSJNMiAyaDI0djI0SDJ6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTkgMTZIN3Y1aDV2LTJIOXYtM3ptLTItNGgyVjloM1Y3SDd2NXptMTIgN2gtM3YyaDV2LTVoLTJ2M3pNMTYgN3YyaDN2M2gyVjdoLTV6Ii8+PC9zdmc+\");\n}\n\n.svg-exit-fullscreen button,\nbutton.svg-exit-fullscreen {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAyOCAyOCIgd2lkdGg9IjI4Ij48cGF0aCBkPSJNMiAyaDI0djI0SDJ6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTcgMThoM3YzaDJ2LTVIN3Yyem0zLThIN3YyaDVWN2gtMnYzem02IDExaDJ2LTNoM3YtMmgtNXY1em0yLTExVjdoLTJ2NWg1di0yaC0zeiIvPjwvc3ZnPg==\");\n}\n\n.svg-twizzle-tw button,\nbutton.svg-twizzle-tw {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODY0IiBoZWlnaHQ9IjYwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMzk3LjU4MSAxNTEuMTh2NTcuMDg0aC04OS43MDN2MjQwLjM1MmgtNjYuOTU1VjIwOC4yNjRIMTUxLjIydi01Ny4wODNoMjQ2LjM2MXptNTQuMzEgNzEuNjc3bDcuNTEyIDMzLjY5MmMyLjcxOCAxMi4xNiA1LjU4IDI0LjY4IDguNTg0IDM3LjU1NWEyMTgwLjc3NSAyMTgwLjc3NSAwIDAwOS40NDIgMzguODQzIDEyNjYuMyAxMjY2LjMgMCAwMDEwLjA4NiAzNy41NTVjMy43Mi0xMi41OSA3LjM2OC0yNS40NjYgMTAuOTQ1LTM4LjYyOCAzLjU3Ni0xMy4xNjIgNy4wMS0yNi4xMSAxMC4zLTM4Ljg0M2w1Ljc2OS0yMi40NTZjMS4yNDgtNC44ODcgMi40NzItOS43MDUgMy42NzQtMTQuNDU1IDMuMDA0LTExLjg3NSA1LjY1MS0yMi45NjIgNy45NC0zMy4yNjNoNDYuMzU0bDIuMzg0IDEwLjU2M2EyMDAwLjc3IDIwMDAuNzcgMCAwMDMuOTM1IDE2LjgyOGw2LjcxMSAyNy43MWMxLjIxMyA0Ljk1NiAyLjQ1IDkuOTggMy43MDkgMTUuMDczYTMxMTkuNzc3IDMxMTkuNzc3IDAgMDA5Ljg3MSAzOC44NDMgMTI0OS4yMjcgMTI0OS4yMjcgMCAwMDEwLjczIDM4LjYyOCAxOTA3LjYwNSAxOTA3LjYwNSAwIDAwMTAuMzAxLTM3LjU1NSAxMzk3Ljk0IDEzOTcuOTQgMCAwMDkuNjU3LTM4Ljg0M2w0LjQtMTkuMDQ2Yy43MTUtMy4xMyAxLjQyMS02LjIzNiAyLjExOC05LjMyMWw5LjU3Ny00Mi44OGg2Ni41MjZhMjk4OC43MTggMjk4OC43MTggMCAwMS0xOS41MjkgNjYuMzExbC01LjcyOCAxOC40ODJhMzIzNy40NiAzMjM3LjQ2IDAgMDEtMTQuMDE1IDQzLjc1MmMtNi40MzggMTkuNi0xMi43MzMgMzcuNjk4LTE4Ljg4NSA1NC4yOTRsLTMuMzA2IDguODI1Yy00Ljg4NCAxMi44OTgtOS40MzMgMjQuMjYzLTEzLjY0NyAzNC4wOTVoLTQ5Ljc4N2E4NDE3LjI4OSA4NDE3LjI4OSAwIDAxLTIxLjAzMS02NC44MDkgMTI4OC42ODYgMTI4OC42ODYgMCAwMS0xOC44ODUtNjQuODEgMTk3Mi40NDQgMTk3Mi40NDQgMCAwMS0xOC4yNCA2NC44MSAyNTc5LjQxMiAyNTc5LjQxMiAwIDAxLTIwLjM4OCA2NC44MWgtNDkuNzg3Yy00LjY4Mi0xMC45MjYtOS43Mi0yMy43NDMtMTUuMTEtMzguNDUxbC0xLjYyOS00LjQ3Yy01LjI1OC0xNC41MjEtMTAuNjgtMzAuMTkyLTE2LjI2Ni00Ny4wMTRsLTIuNDA0LTcuMjhjLTYuNDM4LTE5LjYtMTMuMDItNDAuMzQ0LTE5Ljc0My02Mi4yMzRhMjk4OC43MDcgMjk4OC43MDcgMCAwMS0xOS41MjktNjYuMzExaDY3LjM4NXoiIGZpbGw9IiM0Mjg1RjQiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==\");\n}\n`);\n\n// Sized against full-screen dimensions.\n// button.svg-twizzle-tw {\n// background-image: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzc3IiBoZWlnaHQ9IjUxMyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMzU0LjU4MSAxMDcuMTh2NTcuMDg0aC04OS43MDN2MjQwLjM1MmgtNjYuOTU1VjE2NC4yNjRIMTA4LjIydi01Ny4wODNoMjQ2LjM2MXptNTQuMzEgNzEuNjc3bDcuNTEyIDMzLjY5MmMyLjcxOCAxMi4xNiA1LjU4IDI0LjY4IDguNTg0IDM3LjU1NWEyMTgwLjc3NSAyMTgwLjc3NSAwIDAwOS40NDIgMzguODQzIDEyNjYuMyAxMjY2LjMgMCAwMDEwLjA4NiAzNy41NTVjMy43Mi0xMi41OSA3LjM2OC0yNS40NjYgMTAuOTQ1LTM4LjYyOCAzLjU3Ni0xMy4xNjIgNy4wMS0yNi4xMSAxMC4zLTM4Ljg0M2w1Ljc2OS0yMi40NTZjMS4yNDgtNC44ODcgMi40NzItOS43MDUgMy42NzQtMTQuNDU1IDMuMDA0LTExLjg3NSA1LjY1MS0yMi45NjIgNy45NC0zMy4yNjNoNDYuMzU0bDIuMzg0IDEwLjU2M2EyMDAwLjc3IDIwMDAuNzcgMCAwMDMuOTM1IDE2LjgyOGw2LjcxMSAyNy43MWMxLjIxMyA0Ljk1NiAyLjQ1IDkuOTggMy43MDkgMTUuMDczYTMxMTkuNzc3IDMxMTkuNzc3IDAgMDA5Ljg3MSAzOC44NDMgMTI0OS4yMjcgMTI0OS4yMjcgMCAwMDEwLjczIDM4LjYyOCAxOTA3LjYwNSAxOTA3LjYwNSAwIDAwMTAuMzAxLTM3LjU1NSAxMzk3Ljk0IDEzOTcuOTQgMCAwMDkuNjU3LTM4Ljg0M2w0LjQtMTkuMDQ2Yy43MTUtMy4xMyAxLjQyMS02LjIzNiAyLjExOC05LjMyMWw5LjU3Ny00Mi44OGg2Ni41MjZhMjk4OC43MTggMjk4OC43MTggMCAwMS0xOS41MjkgNjYuMzExbC01LjcyOCAxOC40ODJhMzIzNy40NiAzMjM3LjQ2IDAgMDEtMTQuMDE1IDQzLjc1MmMtNi40MzggMTkuNi0xMi43MzMgMzcuNjk4LTE4Ljg4NSA1NC4yOTRsLTMuMzA2IDguODI1Yy00Ljg4NCAxMi44OTgtOS40MzMgMjQuMjYzLTEzLjY0NyAzNC4wOTVoLTQ5Ljc4N2E4NDE3LjI4OSA4NDE3LjI4OSAwIDAxLTIxLjAzMS02NC44MDkgMTI4OC42ODYgMTI4OC42ODYgMCAwMS0xOC44ODUtNjQuODEgMTk3Mi40NDQgMTk3Mi40NDQgMCAwMS0xOC4yNCA2NC44MSAyNTc5LjQxMiAyNTc5LjQxMiAwIDAxLTIwLjM4OCA2NC44MWgtNDkuNzg3Yy00LjY4Mi0xMC45MjYtOS43Mi0yMy43NDMtMTUuMTEtMzguNDUxbC0xLjYyOS00LjQ3Yy01LjI1OC0xNC41MjEtMTAuNjgtMzAuMTkyLTE2LjI2Ni00Ny4wMTRsLTIuNDA0LTcuMjhjLTYuNDM4LTE5LjYtMTMuMDItNDAuMzQ0LTE5Ljc0My02Mi4yMzRhMjk4OC43MDcgMjk4OC43MDcgMCAwMS0xOS41MjktNjYuMzExaDY3LjM4NXoiIGZpbGw9IiM0Mjg1RjQiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==\");\n// }\n", "// Use like this:\n// const enabled = globalSafeDocument?.fullscreenEnabled;\nexport const globalSafeDocument: Document | null =\n typeof document === \"undefined\" ? null : document;\n", "// Ponyfills for prefixing in Safari.\n\nimport { globalSafeDocument } from \"../document\";\n\ndeclare global {\n interface Document {\n webkitFullscreenEnabled?: boolean;\n webkitExitFullscreen?: () => Promise<void>;\n webkitFullscreenElement?: Element | null;\n }\n\n interface Element {\n webkitRequestFullscreen: () => Promise<void>;\n }\n}\n\n// TODO: Can `webkitFullscreenEnabled` change after it's cached at page load?\nexport const fullscreenEnabled: boolean =\n globalSafeDocument?.fullscreenEnabled ||\n !!globalSafeDocument?.webkitFullscreenEnabled;\n\nexport function documentExitFullscreen(): Promise<void> {\n if (document.exitFullscreen) {\n return document.exitFullscreen();\n } else {\n return document.webkitExitFullscreen!(); // YOLO\n }\n}\n\nexport function documentFullscreenElement(): Element | null {\n if (document.fullscreenElement) {\n return document.fullscreenElement;\n } else {\n return document.webkitFullscreenElement ?? null;\n }\n}\n\nexport function requestFullscreen(element: Element): Promise<void> {\n if (element.requestFullscreen) {\n return element.requestFullscreen();\n } else {\n return element.webkitRequestFullscreen();\n }\n}\n", "import type { ButtonCommand } from \"../../../views/control-panel/TwistyButtons\";\nimport { fullscreenEnabled } from \"../../../views/control-panel/webkit-fullscreen\";\nimport type { ViewerLinkPageWithAuto } from \"./ViewerLinkProp\";\nimport type { CoarseTimelineInfo as CoarseTimelineInfo } from \"../timeline/CoarseTimelineInfoProp\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\n\nexport const buttonIcons = [\n \"skip-to-start\",\n \"skip-to-end\",\n \"step-forward\",\n \"step-backward\",\n \"pause\",\n \"play\",\n \"enter-fullscreen\",\n \"exit-fullscreen\",\n \"twizzle-tw\",\n];\nexport type ButtonIcon = typeof buttonIcons[number];\n\ninterface ButtonAppearance {\n enabled: boolean;\n icon: ButtonIcon;\n title: string;\n hidden?: boolean;\n}\nexport type ButtonAppearances = Record<ButtonCommand, ButtonAppearance>;\n\n// TODO: reduce inputs to avoid unnecessary updates.\ninterface ButtonAppearancePropInputs {\n coarseTimelineInfo: CoarseTimelineInfo;\n viewerLink: ViewerLinkPageWithAuto;\n}\n\nexport class ButtonAppearanceProp extends TwistyPropDerived<\n ButtonAppearancePropInputs,\n ButtonAppearances\n> {\n // TODO: This still seems to fire twice for play/pause?\n derive(inputs: ButtonAppearancePropInputs): ButtonAppearances {\n const buttonAppearances = {\n \"fullscreen\": {\n // TODO: Cache?// TODO: Cache?\n enabled: fullscreenEnabled,\n icon:\n // TODO: Check against the expected element?\n // TODO: This will *not* update when we enter/leave fullscreen. We need to work more closely with the controller.\n document.fullscreenElement === null\n ? \"enter-fullscreen\"\n : \"exit-fullscreen\",\n title: \"Enter fullscreen\",\n },\n \"jump-to-start\": {\n enabled: !inputs.coarseTimelineInfo.atStart,\n icon: \"skip-to-start\",\n title: \"Restart\",\n },\n \"play-step-backwards\": {\n enabled: !inputs.coarseTimelineInfo.atStart,\n icon: \"step-backward\",\n title: \"Step backward\",\n },\n \"play-pause\": {\n enabled: !(\n inputs.coarseTimelineInfo.atStart && inputs.coarseTimelineInfo.atEnd\n ),\n icon: inputs.coarseTimelineInfo.playing ? \"pause\" : \"play\",\n title: inputs.coarseTimelineInfo.playing ? \"Pause\" : \"Play\",\n },\n \"play-step\": {\n enabled: !inputs.coarseTimelineInfo.atEnd,\n icon: \"step-forward\",\n title: \"Step forward\",\n },\n \"jump-to-end\": {\n enabled: !inputs.coarseTimelineInfo.atEnd,\n icon: \"skip-to-end\",\n title: \"Skip to End\",\n },\n \"twizzle-link\": {\n enabled: true,\n icon: \"twizzle-tw\",\n title: \"View at Twizzle\",\n hidden: inputs.viewerLink === \"none\",\n },\n };\n return buttonAppearances;\n }\n}\n", "import { BoundaryType, Direction } from \"../../controllers/AnimationTypes\";\nimport { buttonCSS, buttonGridCSS } from \"./TwistyButtons.css\";\nimport { ClassListManager } from \"../ClassListManager\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport {\n ButtonAppearances,\n ButtonIcon,\n buttonIcons,\n} from \"../../model/props/viewer/ButtonAppearanceProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport type { TwistyPlayerController } from \"../../controllers/TwistyPlayerController\";\nimport {\n documentExitFullscreen,\n documentFullscreenElement,\n requestFullscreen,\n} from \"./webkit-fullscreen\";\n\nconst buttonCommands = {\n \"fullscreen\": true,\n \"jump-to-start\": true,\n \"play-step-backwards\": true,\n \"play-pause\": true,\n \"play-step\": true,\n \"jump-to-end\": true,\n \"twizzle-link\": true,\n};\n\nexport type ButtonCommand = keyof typeof buttonCommands;\n\nexport class TwistyButtons extends ManagedCustomElement {\n buttons: Record<ButtonCommand, TwistyButton> | null = null;\n\n // TODO: Privacy\n constructor(\n public model?: TwistyPlayerModel,\n public controller?: TwistyPlayerController,\n private fullscreenElement?: HTMLElement,\n ) {\n super();\n }\n\n connectedCallback(): void {\n this.addCSS(buttonGridCSS);\n const buttons: Partial<Record<ButtonCommand, TwistyButton>> = {};\n for (const command in buttonCommands) {\n const button = new TwistyButton();\n buttons[command as ButtonCommand] = button;\n // Why does this still fire with the `disabled` attribute?\n button.addEventListener(\"click\", () =>\n this.#onCommand(command as ButtonCommand),\n );\n this.addElement(button);\n }\n this.buttons = buttons as Record<ButtonCommand, TwistyButton>;\n\n this.model?.buttonAppearance.addFreshListener(this.update.bind(this));\n }\n\n #onCommand(command: ButtonCommand) {\n switch (command) {\n case \"fullscreen\":\n this.onFullscreenButton();\n break;\n case \"jump-to-start\":\n this.controller?.jumpToStart({ flash: true });\n break;\n case \"play-step-backwards\":\n this.controller?.animationController.play({\n direction: Direction.Backwards,\n untilBoundary: BoundaryType.Move,\n });\n break;\n case \"play-pause\":\n this.controller?.togglePlay();\n break;\n case \"play-step\":\n this.controller?.animationController.play({\n direction: Direction.Forwards,\n untilBoundary: BoundaryType.Move,\n });\n break;\n case \"jump-to-end\":\n this.controller?.jumpToEnd({ flash: true });\n break;\n case \"twizzle-link\":\n this.controller?.visitTwizzleLink();\n break;\n default:\n throw new Error(\"Missing command\");\n }\n }\n\n // TODO: Should we have a prop, or a way to query if we're fullscreen?\n // https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullScreen\n async onFullscreenButton(): Promise<void> {\n if (!this.fullscreenElement) {\n throw new Error(\"Attempted to go fullscreen without an element.\");\n }\n\n if (documentFullscreenElement() === this.fullscreenElement) {\n documentExitFullscreen();\n } else {\n // TODO: Propagate button info to `ButtonAppearanceProp`.\n this.buttons?.fullscreen.setIcon(\"exit-fullscreen\");\n\n requestFullscreen(this.fullscreenElement);\n\n const onFullscreen = (): void => {\n if (documentFullscreenElement() !== this.fullscreenElement) {\n this.buttons?.fullscreen.setIcon(\"enter-fullscreen\");\n window.removeEventListener(\"fullscreenchange\", onFullscreen);\n }\n };\n window.addEventListener(\"fullscreenchange\", onFullscreen);\n }\n }\n\n async update(buttonAppearances: ButtonAppearances): Promise<void> {\n // TODO: Check that we have every command?\n for (const command in buttonCommands) {\n // TODO: Why doesn't `command` have the type `ButtonCommand`?\n const button = this.buttons![command as ButtonCommand];\n // TODO: track individual changes?\n const info = buttonAppearances[command as ButtonCommand];\n button.button.disabled = !info.enabled;\n button.button.title = info.title;\n button.setIcon(info.icon);\n button.hidden = !!info.hidden;\n // button.textContent = info.icon;\n }\n }\n}\n\ncustomElementsShim.define(\"twisty-buttons\", TwistyButtons);\n\nclass TwistyButton extends ManagedCustomElement {\n button: HTMLButtonElement = document.createElement(\"button\"); // TODO: async?\n\n connectedCallback() {\n this.addCSS(buttonCSS);\n this.addElement(this.button);\n }\n\n #iconManager: ClassListManager<ButtonIcon> = new ClassListManager(\n this,\n \"svg-\",\n buttonIcons,\n );\n\n setIcon(iconName: ButtonIcon): void {\n this.#iconManager.setValue(iconName);\n }\n}\n\ncustomElementsShim.define(\"twisty-button\", TwistyButton);\n", "import { CSSSource } from \"../ManagedCustomElement\";\n\nexport const twistyScrubberCSS = new CSSSource(`\n:host {\n width: 384px;\n height: 16px;\n display: grid;\n}\n\n.wrapper {\n width: 100%;\n height: 100%;\n display: grid;\n overflow: hidden;\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n background: rgba(196, 196, 196, 0.75)\n}\n\ninput:not(:disabled) {\n cursor: ew-resize;\n}\n`);\n", "import { twistyScrubberCSS } from \"./TwistyScrubber.css\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport type { DetailedTimelineInfo } from \"../../model/props/timeline/DetailedTimelineInfoProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { globalSafeDocument } from \"../document\";\n\nconst SLOW_DOWN_SCRUBBING = false;\n\nlet isMouseDown = false;\n\nglobalSafeDocument?.addEventListener(\n \"mousedown\",\n function (event) {\n if (event.which) {\n isMouseDown = true;\n }\n },\n true,\n);\n\nglobalSafeDocument?.addEventListener(\n \"mouseup\",\n function (event) {\n if (event.which) {\n isMouseDown = false;\n }\n },\n true,\n);\n\n// var x = 0;\nlet y = 0;\nlet clickNum = 0;\n\nglobalSafeDocument?.addEventListener(\n \"mousedown\",\n () => {\n clickNum++;\n },\n false,\n);\n\nglobalSafeDocument?.addEventListener(\"mousemove\", onMouseUpdate, false);\nglobalSafeDocument?.addEventListener(\"mouseenter\", onMouseUpdate, false);\n\nfunction onMouseUpdate(e: MouseEvent) {\n // x = e.pageX;\n y = e.pageY;\n // console.log(x, y);\n}\n\nconst lastVal = 0;\nlet lastPreval = 0;\nlet scaling: boolean = false;\nlet currentClickNum = 0;\n\n// Values are integers.\nexport class TwistyScrubber extends ManagedCustomElement {\n constructor(public model?: TwistyPlayerModel) {\n super();\n }\n\n async onDetailedTimelineInfo(\n detailedTimelineInfo: DetailedTimelineInfo,\n ): Promise<void> {\n // TODO: is this efficient enough?\n const inputElem = await this.inputElem();\n inputElem.min = detailedTimelineInfo.timeRange.start.toString();\n inputElem.max = detailedTimelineInfo.timeRange.end.toString();\n inputElem.disabled = inputElem.min === inputElem.max;\n inputElem.value = detailedTimelineInfo.timestamp.toString();\n }\n\n async connectedCallback(): Promise<void> {\n this.addCSS(twistyScrubberCSS);\n this.addElement(await this.inputElem());\n }\n\n #inputElem: Promise<HTMLInputElement> | null = null;\n async inputElem(): Promise<HTMLInputElement> {\n // console.log(\"inputElem\", this.#inputElem);\n return (this.#inputElem ??= (async () => {\n const elem = document.createElement(\"input\");\n elem.type = \"range\";\n elem.disabled = true;\n\n // console.log(\"1\");\n this.model?.detailedTimelineInfo.addFreshListener(\n this.onDetailedTimelineInfo.bind(this),\n );\n // console.log(\"3\");\n elem.addEventListener(\"input\", this.onInput.bind(this));\n\n return elem;\n })());\n }\n\n async onInput(e: Event): Promise<void> {\n if (scaling) {\n return; // TODO\n }\n const inputElem = await this.inputElem();\n await this.slowDown(e, inputElem); // TODO\n\n const value = parseInt(inputElem.value);\n // console.log(\"on input\", value);\n this.model?.playingInfo.set({ playing: false });\n this.model?.timestampRequest.set(value);\n }\n\n async slowDown(e: Event, inputElem: HTMLInputElement): Promise<void> {\n if (!SLOW_DOWN_SCRUBBING) {\n return; // TODO\n }\n\n if (isMouseDown) {\n const rect = inputElem.getBoundingClientRect();\n const sliderY = rect.top + rect.height / 2;\n console.log(sliderY, e, y, isMouseDown);\n\n const yDist = Math.abs(sliderY - y);\n let scale = 1;\n if (yDist > 64) {\n scale = Math.max(Math.pow(2, -(yDist - 64) / 64), 1 / 32);\n }\n const preVal = parseInt(inputElem.value);\n console.log(\"cl\", currentClickNum, clickNum, preVal);\n if (currentClickNum === clickNum) {\n const delta = (preVal - lastPreval) * scale;\n console.log(\"delta\", delta, yDist);\n scaling = true;\n let newVal = preVal;\n newVal =\n lastVal +\n delta * scale +\n (preVal - lastVal) *\n Math.min(1, Math.pow(1 / 2, (yDist * yDist) / 64));\n inputElem.value = newVal.toString();\n console.log(scale);\n scaling = false;\n this.contentWrapper.style.opacity = scale.toString();\n } else {\n currentClickNum = clickNum;\n }\n lastPreval = preVal;\n }\n }\n}\n\ncustomElementsShim.define(\"twisty-scrubber\", TwistyScrubber);\n", "import type { PerspectiveCamera } from \"three\";\nimport { THREEJS } from \"../heavy-code-imports/3d\";\nimport type { TwistyPlayerModel } from \"../model/TwistyPlayerModel\";\nimport { Twisty3DPuzzleWrapper } from \"./3D/Twisty3DPuzzleWrapper\";\nimport { setCameraFromOrbitCoordinates } from \"./3D/Twisty3DVantage\";\n\nexport interface TwistyPlayerScreenshot {\n dataURL: string;\n download: (filename?: string) => Promise<void>;\n}\n\n// TODO: cache\nlet cachedCamera: PerspectiveCamera | null = null;\nexport async function screenshot(\n model: TwistyPlayerModel,\n options?: { width: number; height: number },\n): Promise<TwistyPlayerScreenshot> {\n // TODO: improve async caching\n\n const width = options?.width ?? 2048;\n const height = options?.height ?? 2048;\n const aspectRatio = width / height;\n const camera = (cachedCamera ??= await (async () => {\n return new (await THREEJS).PerspectiveCamera(20, aspectRatio, 0.1, 20);\n })());\n\n const scene = new (await THREEJS).Scene();\n\n const twisty3DWrapper = new Twisty3DPuzzleWrapper(\n model,\n { scheduleRender: () => {} },\n await model.puzzleLoader.get(),\n await model.visualizationStrategy.get(),\n );\n\n // TODO: Pass the stickering to the constructor so we don't have to wait..\n await model.twistySceneModel.stickering.get();\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n // TODO: Find a more robust way to do this.\n await model.legacyPosition.get(); // Force the 3D puzzle listeners for the state to fire.\n\n scene.add(await twisty3DWrapper.twisty3DPuzzle());\n\n const orbitCoordinates = await model.twistySceneModel.orbitCoordinates.get();\n await setCameraFromOrbitCoordinates(camera, orbitCoordinates);\n\n const renderer = new (await THREEJS).WebGLRenderer({\n antialias: true,\n alpha: true,\n });\n renderer.setSize(width, height);\n\n renderer.render(scene, camera);\n const dataURL = renderer.domElement.toDataURL();\n\n const defaultFilename = await getDefaultFilename(model);\n\n return {\n dataURL,\n download: async (filename?: string) => {\n downloadURL(dataURL, filename ?? defaultFilename);\n },\n };\n}\n\nexport async function getDefaultFilename(\n model: TwistyPlayerModel,\n): Promise<string> {\n const [puzzleID, algWithIssues] = await Promise.all([\n model.puzzleID.get(),\n model.alg.get(),\n ]);\n return `[${puzzleID}]${\n algWithIssues.alg.experimentalNumUnits() === 0\n ? \"\"\n : \" \" + algWithIssues.alg.toString()\n }`;\n}\n\nexport function downloadURL(\n url: string,\n name: string,\n extension: string = \"png\",\n): void {\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${name}.${extension}`;\n a.click();\n}\n", "import { CSSSource } from \"./ManagedCustomElement\";\n\n// TODO: figure out why `:host(twisty-player):fullscreen { background-color: white }` doesn't work.\nexport const twistyPlayerCSS = new CSSSource(`\n:host {\n width: 384px;\n height: 256px;\n display: grid;\n\n -webkit-user-select: none;\n user-select: none;\n}\n\n.wrapper {\n display: grid;\n overflow: hidden;\n grid-template-rows: 7fr minmax(1.5em, 0.5fr) minmax(2em, 1fr);\n}\n\n.wrapper > * {\n width: inherit;\n height: inherit;\n overflow: hidden;\n}\n\n.wrapper.controls-none {\n grid-template-rows: 7fr;\n}\n\n.wrapper.controls-none twisty-scrubber,\n.wrapper.controls-none twisty-control-button-panel ,\n.wrapper.controls-none twisty-scrubber,\n.wrapper.controls-none twisty-buttons {\n display: none;\n}\n\ntwisty-scrubber {\n background: rgba(196, 196, 196, 0.5);\n}\n\n.wrapper.checkered {\n background-color: #EAEAEA;\n background-image: linear-gradient(45deg, #DDD 25%, transparent 25%, transparent 75%, #DDD 75%, #DDD),\n linear-gradient(45deg, #DDD 25%, transparent 25%, transparent 75%, #DDD 75%, #DDD);\n background-size: 32px 32px;\n background-position: 0 0, 16px 16px;\n}\n\n.visualization-wrapper > * {\n width: 100%;\n height: 100%;\n}\n\n.error-elem {\n width: 100%;\n height: 100%;\n display: none;\n place-content: center;\n font-family: sans-serif;\n box-shadow: inset 0 0 2em rgb(255, 0, 0);\n color: red;\n text-shadow: 0 0 0.2em white;\n background: rgba(255, 255, 255, 0.25);\n}\n\n.wrapper.error .visualization-wrapper {\n display: none;\n}\n\n.wrapper.error .error-elem {\n display: grid;\n}\n`);\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nexport class ArbitraryStringProp extends SimpleTwistyPropSource<string | null> {\n getDefaultValue(): string | null {\n return null;\n }\n}\n", "import { TwistyPropSource } from \"../TwistyProp\";\n\nexport class URLProp extends TwistyPropSource<URL | null, URL | string | null> {\n getDefaultValue(): URL | null {\n return null;\n }\n\n derive(input: URL | string | null): URL | null {\n if (typeof input === \"string\") {\n return new URL(input, location.href); // TODO\n }\n return input;\n }\n}\n", "import { Alg } from \"../../../../../alg\";\nimport { arrayEquals } from \"../../../helpers\";\nimport { TwistyPropSource } from \"../../TwistyProp\";\n\nexport class AlgIssues {\n // TODO: (string | Error)[]\n\n readonly warnings: readonly string[];\n readonly errors: readonly string[];\n\n constructor(issues?: { warnings?: string[]; errors?: string[] }) {\n // TODO: clone inputs?\n this.warnings = Object.freeze(issues?.warnings ?? []);\n this.errors = Object.freeze(issues?.errors ?? []);\n Object.freeze(this);\n }\n\n add(issues?: { warnings?: string[]; errors?: string[] }) {\n return new AlgIssues({\n warnings: this.warnings.concat(issues?.warnings ?? []),\n errors: this.errors.concat(issues?.errors ?? []),\n });\n }\n\n /** @deprecated */\n log() {\n if (this.errors.length > 0) {\n console.error(`\uD83D\uDEA8 ${this.errors[0]}`);\n } else if (this.warnings.length > 0) {\n console.warn(`\u26A0\uFE0F ${this.warnings[0]}`);\n } else {\n console.info(\"\uD83D\uDE0E No issues!\");\n }\n }\n}\n\nexport interface AlgWithIssues {\n alg: Alg;\n issues: AlgIssues;\n}\n\nexport function algWithIssuesFromString(s: string): AlgWithIssues {\n try {\n const alg = Alg.fromString(s); // TODO: is this safe?\n const warnings = [];\n if (alg.toString() !== s) {\n // TODO: Push this check into the parser and return semantic info (so they can be e.g. highlighted).\n warnings.push(`Alg is non-canonical!`);\n }\n return {\n alg,\n issues: new AlgIssues({ warnings }),\n };\n } catch (e) {\n return {\n alg: new Alg(),\n issues: new AlgIssues({\n errors: [`Malformed alg: ${(e as Error).toString()}`],\n }),\n };\n }\n}\n\nfunction algWithIssuesEquals(a1: AlgWithIssues, a2: AlgWithIssues): boolean {\n return (\n a1.alg.isIdentical(a2.alg) &&\n arrayEquals(a1.issues.warnings, a2.issues.warnings) &&\n arrayEquals(a1.issues.errors, a2.issues.errors)\n );\n}\n\nexport class AlgProp extends TwistyPropSource<AlgWithIssues, Alg | string> {\n getDefaultValue(): AlgWithIssues {\n return { alg: new Alg(), issues: new AlgIssues() };\n }\n\n canReuseValue(v1: AlgWithIssues, v2: AlgWithIssues) {\n return algWithIssuesEquals(v1, v2);\n }\n\n async derive(newAlg: Alg | string): Promise<AlgWithIssues> {\n if (typeof newAlg === \"string\") {\n return algWithIssuesFromString(newAlg);\n } else {\n return {\n alg: newAlg,\n issues: new AlgIssues(),\n };\n }\n }\n}\n", "import type { KPuzzle, KTransformation } from \"../../../../../kpuzzle\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { AlgWithIssues } from \"./AlgProp\";\n\ntype AlgTransformationPropInputs = {\n setupAlg: AlgWithIssues;\n kpuzzle: KPuzzle;\n};\n\nexport class AlgTransformationProp extends TwistyPropDerived<\n AlgTransformationPropInputs,\n KTransformation\n> {\n derive(input: AlgTransformationPropInputs): KTransformation {\n return input.kpuzzle.algToTransformation(input.setupAlg.alg);\n }\n}\n", "import type { KTransformation } from \"../../../../../kpuzzle\";\nimport type { AlgIndexer } from \"../../../../controllers/indexer/AlgIndexer\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { SetupToLocation } from \"./SetupAnchorProp\";\n\ninterface AnchorTransformationPropInputs {\n setupTransformation: KTransformation | null;\n setupAnchor: SetupToLocation;\n setupAlgTransformation: KTransformation;\n indexer: AlgIndexer;\n}\n\nexport class AnchorTransformationProp extends TwistyPropDerived<\n AnchorTransformationPropInputs,\n KTransformation\n> {\n derive(inputs: AnchorTransformationPropInputs): KTransformation {\n if (inputs.setupTransformation) {\n return inputs.setupTransformation;\n }\n switch (inputs.setupAnchor) {\n case \"start\":\n return inputs.setupAlgTransformation;\n case \"end\": {\n const algTransformation = inputs.indexer.transformationAtIndex(\n inputs.indexer.numAnimatedLeaves(),\n );\n const inverseAlgTransformation = algTransformation.invert();\n return inputs.setupAlgTransformation.applyTransformation(\n inverseAlgTransformation,\n );\n }\n default:\n throw new Error(\"Unimplemented!\");\n }\n }\n}\n", "import type { Move } from \"../../../../../alg\";\nimport { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport interface CatchUpMove {\n move: Move | null;\n amount: number;\n}\n\nexport class CatchUpMoveProp extends SimpleTwistyPropSource<CatchUpMove> {\n getDefaultValue(): CatchUpMove {\n return { move: null, amount: 0 };\n }\n\n canReuseValue(v1: CatchUpMove, v2: CatchUpMove) {\n return v1.move === v2.move && v1.amount === v2.amount;\n }\n}\n", "import type { Move } from \"../../../../../alg\";\nimport type { CurrentMoveInfo } from \"../../../../controllers/indexer/AlgIndexer\";\nimport { arrayEqualsCompare } from \"../../../helpers\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\n\ninterface CurrentLeavesSimplifiedPropInputs {\n currentMoveInfo: CurrentMoveInfo;\n}\n\nexport interface CurrentLeavesSimplified {\n stateIndex: number;\n movesFinishing: Move[];\n movesFinished: Move[];\n}\n\n// This started as a version of `CurrentLeaves` without highly timestamp-sensitive info like fractions, to enable easier caching.\nexport class CurrentLeavesSimplifiedProp extends TwistyPropDerived<\n CurrentLeavesSimplifiedPropInputs,\n CurrentLeavesSimplified\n> {\n derive(inputs: CurrentLeavesSimplifiedPropInputs): CurrentLeavesSimplified {\n return {\n stateIndex: inputs.currentMoveInfo.stateIndex,\n movesFinishing: inputs.currentMoveInfo.movesFinishing.map(\n (currentMoveInfo) => currentMoveInfo.move,\n ),\n movesFinished: inputs.currentMoveInfo.movesFinished.map(\n (currentMoveInfo) => currentMoveInfo.move,\n ),\n };\n }\n\n canReuse(v1: CurrentLeavesSimplified, v2: CurrentLeavesSimplified): boolean {\n return (\n v1.stateIndex === v2.stateIndex &&\n arrayEqualsCompare(\n v1.movesFinishing,\n v2.movesFinishing,\n (m1: Move, m2: Move) => m1.isIdentical(m2),\n ) &&\n arrayEqualsCompare(\n v1.movesFinished,\n v2.movesFinished,\n (m1: Move, m2: Move) => m1.isIdentical(m2),\n )\n );\n }\n}\n", "import { Move } from \"../../../../../alg\";\nimport { Direction } from \"../../../../controllers/AnimationTypes\";\nimport type {\n AlgIndexer,\n CurrentMoveInfo,\n} from \"../../../../controllers/indexer/AlgIndexer\";\nimport type { DetailedTimelineInfo } from \"../../timeline/DetailedTimelineInfoProp\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { CatchUpMove } from \"./CatchUpMoveProp\";\n\ninterface PositionPropInputs {\n indexer: AlgIndexer;\n detailedTimelineInfo: DetailedTimelineInfo;\n catchUpMove: CatchUpMove;\n}\n\n// TODO: Rename \"current\" (implies a single one) to \"active\"?\nexport class CurrentMoveInfoProp extends TwistyPropDerived<\n PositionPropInputs,\n CurrentMoveInfo\n> {\n derive(inputs: PositionPropInputs): CurrentMoveInfo {\n function addCatchUpMove(currentMoveInfo: CurrentMoveInfo): CurrentMoveInfo {\n if (\n inputs.detailedTimelineInfo.atEnd &&\n inputs.catchUpMove.move !== null\n ) {\n currentMoveInfo.currentMoves.push({\n move: inputs.catchUpMove.move,\n direction: Direction.Backwards,\n fraction: 1 - inputs.catchUpMove.amount,\n startTimestamp: -1, // TODO\n endTimestamp: -1, // TODO\n });\n }\n return currentMoveInfo;\n }\n\n // Copied from AlgCursor\n if (inputs.indexer.currentMoveInfo) {\n return addCatchUpMove(\n inputs.indexer.currentMoveInfo(inputs.detailedTimelineInfo.timestamp),\n );\n } else {\n const idx = inputs.indexer.timestampToIndex(\n inputs.detailedTimelineInfo.timestamp,\n );\n const currentMoveInfo: CurrentMoveInfo = {\n stateIndex: idx,\n currentMoves: [],\n movesFinishing: [],\n movesFinished: [],\n movesStarting: [],\n latestStart: -Infinity,\n earliestEnd: Infinity,\n };\n\n if (inputs.indexer.numAnimatedLeaves() > 0) {\n const move = inputs.indexer.getAnimLeaf(idx)?.as(Move);\n if (!move) {\n return addCatchUpMove(currentMoveInfo);\n }\n const start = inputs.indexer.indexToMoveStartTimestamp(idx);\n const duration = inputs.indexer.moveDuration(idx);\n const fraction =\n (inputs.detailedTimelineInfo.timestamp - start) / duration;\n const end = start + duration;\n const currentMove = {\n move,\n direction: Direction.Forwards,\n fraction,\n startTimestamp: start,\n endTimestamp: end,\n };\n if (fraction === 0) {\n currentMoveInfo.movesStarting.push(currentMove);\n // // TODO: push this into the indexer\n // position.state = combineTransformations(\n // inputs.def,\n // state,\n // transformationForMove(inputs.def, move),\n // ) as Transformation;\n } else if (fraction === 1) {\n currentMoveInfo.movesFinishing.push(currentMove);\n // // TODO: push this into the indexer\n // position.state = combineTransformations(\n // inputs.def,\n // state,\n // transformationForMove(inputs.def, move),\n // ) as Transformation;\n } else {\n // TODO\n currentMoveInfo.currentMoves.push(currentMove);\n currentMoveInfo.latestStart = Math.max(\n currentMoveInfo.latestStart,\n start,\n );\n currentMoveInfo.earliestEnd = Math.min(\n currentMoveInfo.earliestEnd,\n end,\n );\n }\n // }\n // }\n }\n return addCatchUpMove(currentMoveInfo);\n }\n }\n}\n", "import type { KTransformation } from \"../../../../../kpuzzle\";\nimport type { KState } from \"../../../../../kpuzzle/KState\";\nimport type { AlgIndexer } from \"../../../../controllers/indexer/AlgIndexer\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { CurrentLeavesSimplified } from \"./CurrentLeavesSimplified\";\n\ninterface CurrentTransformationPropInputs {\n anchoredStart: KTransformation; // kpuzzle todo: KState?\n currentLeavesSimplified: CurrentLeavesSimplified;\n indexer: AlgIndexer;\n}\n\n// TODO: Make this so we don't have to handle the finishing moves?\nexport class CurrentStateProp extends TwistyPropDerived<\n CurrentTransformationPropInputs,\n KState\n> {\n derive(inputs: CurrentTransformationPropInputs): KState {\n let transformation: KTransformation = inputs.indexer.transformationAtIndex(\n inputs.currentLeavesSimplified.stateIndex,\n );\n transformation = inputs.anchoredStart.applyTransformation(transformation);\n\n // TODO: handle non-commutative finished/finishing/current moves.\n for (const finishingMove of inputs.currentLeavesSimplified.movesFinishing) {\n transformation = transformation.applyMove(finishingMove);\n }\n for (const finishedMove of inputs.currentLeavesSimplified.movesFinished) {\n transformation = transformation.applyMove(finishedMove);\n }\n return transformation.toKState(); // kpuzzle todo\n }\n}\n", "import {\n Alg,\n Grouping,\n LineComment,\n Commutator,\n Conjugate,\n Move,\n Newline,\n Pause,\n TraversalUp,\n} from \"../../../alg\";\nimport type { Duration } from \"../AnimationTypes\";\n\nexport function constantDurationForAmount(_amount: number): Duration {\n return 1000;\n}\n\nexport function defaultDurationForAmount(amount: number): Duration {\n switch (Math.abs(amount)) {\n case 0:\n return 0;\n case 1:\n return 1000;\n case 2:\n return 1500;\n default:\n return 2000;\n }\n}\n// eslint-disable-next-line no-inner-declarations\nexport function ExperimentalScaledDefaultDurationForAmount(\n scale: number,\n amount: number,\n): Duration {\n switch (Math.abs(amount)) {\n case 0:\n return 0;\n case 1:\n return scale * 1000;\n case 2:\n return scale * 1500;\n default:\n return scale * 2000;\n }\n}\n\nexport class AlgDuration extends TraversalUp<Duration> {\n // TODO: Pass durationForAmount as Down type instead?\n constructor(\n public durationForAmount: (\n amount: number,\n ) => Duration = defaultDurationForAmount,\n ) {\n super();\n }\n\n public traverseAlg(alg: Alg): Duration {\n let total = 0;\n for (const unit of alg.units()) {\n total += this.traverseUnit(unit);\n }\n return total;\n }\n\n public traverseGrouping(grouping: Grouping): Duration {\n return grouping.amount * this.traverseAlg(grouping.alg);\n }\n\n public traverseMove(move: Move): Duration {\n return this.durationForAmount(move.amount);\n }\n\n public traverseCommutator(commutator: Commutator): Duration {\n return (\n 2 * (this.traverseAlg(commutator.A) + this.traverseAlg(commutator.B))\n );\n }\n\n public traverseConjugate(conjugate: Conjugate): Duration {\n return 2 * this.traverseAlg(conjugate.A) + this.traverseAlg(conjugate.B);\n }\n\n public traversePause(_pause: Pause): Duration {\n return this.durationForAmount(1);\n }\n\n public traverseNewline(_newline: Newline): Duration {\n return this.durationForAmount(1);\n }\n\n public traverseLineComment(_comment: LineComment): Duration {\n return this.durationForAmount(0);\n }\n}\n", "import { Alg, Move, TraversalUp } from \"../../../alg\";\nimport type { KPuzzle, KTransformation } from \"../../../kpuzzle\";\nimport type { KState } from \"../../../kpuzzle/KState\";\nimport { experimentalCountAnimatedLeaves } from \"../../../notation\";\nimport type { Duration, Timestamp } from \"../AnimationTypes\";\nimport { AlgDuration, defaultDurationForAmount } from \"./AlgDuration\";\nimport type { AlgIndexer } from \"./AlgIndexer\";\n\nexport class SimpleAlgIndexer implements AlgIndexer {\n private moves: Alg;\n // TODO: Allow custom `durationFn`.\n private durationFn: TraversalUp<Duration> = new AlgDuration(\n defaultDurationForAmount,\n );\n\n constructor(private kpuzzle: KPuzzle, alg: Alg) {\n // TODO: Avoid assuming all base moves are block moves.\n this.moves = new Alg(alg.experimentalExpand());\n }\n\n public getAnimLeaf(index: number): Move {\n return Array.from(this.moves.units())[index] as Move; // TODO: perf\n }\n\n public indexToMoveStartTimestamp(index: number): Timestamp {\n const alg = new Alg(Array.from(this.moves.units()).slice(0, index)); // TODO\n return this.durationFn.traverseAlg(alg);\n }\n\n public timestampToIndex(timestamp: Timestamp): number {\n let cumulativeTime = 0;\n let i;\n for (i = 0; i < this.numAnimatedLeaves(); i++) {\n cumulativeTime += this.durationFn.traverseMove(this.getAnimLeaf(i));\n if (cumulativeTime >= timestamp) {\n return i;\n }\n }\n return i;\n }\n\n public stateAtIndex(index: number): KState {\n return this.kpuzzle\n .startState()\n .applyTransformation(this.transformationAtIndex(index));\n }\n\n public transformationAtIndex(index: number): KTransformation {\n let state = this.kpuzzle.identityTransformation();\n for (const move of Array.from(this.moves.units()).slice(0, index)) {\n // TODO\n state = state.applyMove(move as Move);\n }\n return state;\n }\n\n public algDuration(): Duration {\n return this.durationFn.traverseAlg(this.moves);\n }\n\n public numAnimatedLeaves(): number {\n // TODO: Cache internally once performance matters.\n return experimentalCountAnimatedLeaves(this.moves);\n }\n\n public moveDuration(index: number): number {\n return this.durationFn.traverseMove(this.getAnimLeaf(index));\n }\n}\n", "import {\n LineComment,\n Commutator,\n Conjugate,\n Pause,\n TraversalUp,\n Move,\n Alg,\n Grouping,\n Newline,\n} from \"../../../../alg\";\nimport type { MillisecondTimestamp } from \"../../AnimationTypes\";\nimport { defaultDurationForAmount } from \"../AlgDuration\";\n\nexport type AnimatedLeafUnit = Move | Pause;\nexport interface LocalAnimLeavesWithRange {\n animLeafUnit: AnimatedLeafUnit;\n msUntilNext: MillisecondTimestamp;\n duration: MillisecondTimestamp;\n}\n\nexport interface AnimLeafWithRange {\n animLeaf: AnimatedLeafUnit;\n start: MillisecondTimestamp;\n end: MillisecondTimestamp;\n}\n\nconst axisLookup: Record<string, \"x\" | \"y\" | \"z\"> = {\n u: \"y\",\n l: \"x\",\n f: \"z\",\n r: \"x\",\n b: \"z\",\n d: \"y\",\n m: \"x\",\n e: \"y\",\n s: \"z\",\n x: \"x\",\n y: \"y\",\n z: \"z\",\n};\n\nfunction isSameAxis(move1: Move, move2: Move): boolean {\n return (\n axisLookup[move1.family[0].toLowerCase()] ===\n axisLookup[move2.family[0].toLowerCase()]\n );\n}\n\n// TODO: Replace this with an optimized implementation.\n// TODO: Consider `(x U)` and `(U x F)` to be simultaneous.\nexport class LocalSimulMoves extends TraversalUp<LocalAnimLeavesWithRange[]> {\n public traverseAlg(alg: Alg): LocalAnimLeavesWithRange[] {\n const processed: LocalAnimLeavesWithRange[][] = [];\n for (const nestedUnit of alg.units()) {\n processed.push(this.traverseUnit(nestedUnit));\n }\n return Array.prototype.concat(...processed) as LocalAnimLeavesWithRange[];\n }\n\n public traverseGroupingOnce(alg: Alg): LocalAnimLeavesWithRange[] {\n if (alg.experimentalIsEmpty()) {\n return [];\n }\n\n for (const unit of alg.units()) {\n if (!unit.is(Move)) {\n // TODO: define the type statically on the class?\n return this.traverseAlg(alg);\n }\n }\n\n const moves = Array.from(alg.units()) as Move[];\n let maxSimulDur = defaultDurationForAmount(moves[0].amount);\n for (let i = 0; i < moves.length - 1; i++) {\n for (let j = 1; j < moves.length; j++) {\n if (!isSameAxis(moves[i], moves[j])) {\n return this.traverseAlg(alg);\n }\n }\n maxSimulDur = Math.max(\n maxSimulDur,\n defaultDurationForAmount(moves[i].amount),\n );\n }\n\n const localMovesWithRange: LocalAnimLeavesWithRange[] = moves.map(\n (blockMove): LocalAnimLeavesWithRange => {\n return {\n animLeafUnit: blockMove,\n msUntilNext: 0,\n duration: maxSimulDur,\n };\n },\n );\n localMovesWithRange[localMovesWithRange.length - 1].msUntilNext =\n maxSimulDur;\n return localMovesWithRange;\n }\n\n public traverseGrouping(grouping: Grouping): LocalAnimLeavesWithRange[] {\n const processed: LocalAnimLeavesWithRange[][] = [];\n\n const segmentOnce: Alg =\n grouping.amount > 0 ? grouping.alg : grouping.alg.invert();\n for (let i = 0; i < Math.abs(grouping.amount); i++) {\n processed.push(this.traverseGroupingOnce(segmentOnce));\n }\n return Array.prototype.concat(...processed) as LocalAnimLeavesWithRange[];\n }\n\n public traverseMove(move: Move): LocalAnimLeavesWithRange[] {\n const duration = defaultDurationForAmount(move.amount);\n return [\n {\n animLeafUnit: move,\n msUntilNext: duration,\n duration,\n },\n ];\n }\n\n public traverseCommutator(\n commutator: Commutator,\n ): LocalAnimLeavesWithRange[] {\n const processed: LocalAnimLeavesWithRange[][] = [];\n const segmentsOnce: Alg[] = [\n commutator.A,\n commutator.B,\n commutator.A.invert(),\n commutator.B.invert(),\n ];\n for (const segment of segmentsOnce) {\n processed.push(this.traverseGroupingOnce(segment));\n }\n return Array.prototype.concat(...processed) as LocalAnimLeavesWithRange[];\n }\n\n public traverseConjugate(conjugate: Conjugate): LocalAnimLeavesWithRange[] {\n const processed: LocalAnimLeavesWithRange[][] = [];\n const segmentsOnce: Alg[] = [\n conjugate.A,\n conjugate.B,\n conjugate.A.invert(),\n ];\n for (const segment of segmentsOnce) {\n processed.push(this.traverseGroupingOnce(segment));\n }\n return Array.prototype.concat(...processed) as LocalAnimLeavesWithRange[];\n }\n\n public traversePause(pause: Pause): LocalAnimLeavesWithRange[] {\n const duration = defaultDurationForAmount(1);\n return [\n {\n animLeafUnit: pause,\n msUntilNext: duration, // TODO\n duration,\n },\n ];\n }\n\n public traverseNewline(_newline: Newline): LocalAnimLeavesWithRange[] {\n return [];\n }\n\n public traverseLineComment(\n _comment: LineComment,\n ): LocalAnimLeavesWithRange[] {\n return [];\n }\n}\n\nconst localSimulMovesInstance = new LocalSimulMoves();\n\nconst localSimulMoves = localSimulMovesInstance.traverseAlg.bind(\n localSimulMovesInstance,\n) as (a: Alg) => LocalAnimLeavesWithRange[];\n\nexport function simulMoves(a: Alg): AnimLeafWithRange[] {\n let timestamp = 0;\n const l = localSimulMoves(a).map(\n (localSimulMove: LocalAnimLeavesWithRange): AnimLeafWithRange => {\n const leafWithRange = {\n animLeaf: localSimulMove.animLeafUnit,\n start: timestamp,\n end: timestamp + localSimulMove.duration,\n };\n timestamp += localSimulMove.msUntilNext;\n return leafWithRange;\n },\n );\n return l;\n}\n", "import { Alg, Move } from \"../../../../alg\";\nimport type { KPuzzle, KTransformation } from \"../../../../kpuzzle\";\nimport type { KState } from \"../../../../kpuzzle/KState\";\nimport {\n Direction,\n Duration,\n PuzzlePosition,\n Timestamp,\n} from \"../../AnimationTypes\";\nimport type { CurrentMove, CurrentMoveInfo } from \"../AlgIndexer\";\nimport { AnimatedLeafUnit, AnimLeafWithRange, simulMoves } from \"./simul-moves\";\n\nconst demos: Record<string, AnimLeafWithRange[]> = {\n \"y' y' U' E D R2 r2 F2 B2 U E D' R2 L2' z2 S2 U U D D S2 F2' B2\": [\n { animLeaf: new Move(\"y\", -1), start: 0, end: 1000 },\n { animLeaf: new Move(\"y\", -1), start: 1000, end: 2000 },\n { animLeaf: new Move(\"U\", -1), start: 1000, end: 1600 },\n { animLeaf: new Move(\"E\", 1), start: 1200, end: 1800 },\n { animLeaf: new Move(\"D\"), start: 1400, end: 2000 },\n { animLeaf: new Move(\"R\", 2), start: 2000, end: 3500 },\n { animLeaf: new Move(\"r\", 2), start: 2000, end: 3500 },\n { animLeaf: new Move(\"F\", 2), start: 3500, end: 4200 },\n { animLeaf: new Move(\"B\", 2), start: 3800, end: 4500 },\n { animLeaf: new Move(\"U\", 1), start: 4500, end: 5500 },\n { animLeaf: new Move(\"E\", 1), start: 4500, end: 5500 },\n { animLeaf: new Move(\"D\", -1), start: 4500, end: 5500 },\n { animLeaf: new Move(\"R\", 2), start: 5500, end: 6500 },\n { animLeaf: new Move(\"L\", -2), start: 5500, end: 6500 },\n { animLeaf: new Move(\"z\", 2), start: 5500, end: 6500 },\n { animLeaf: new Move(\"S\", 2), start: 6500, end: 7500 },\n { animLeaf: new Move(\"U\"), start: 7500, end: 8000 },\n { animLeaf: new Move(\"D\"), start: 7750, end: 8250 },\n { animLeaf: new Move(\"U\"), start: 8000, end: 8500 },\n { animLeaf: new Move(\"D\"), start: 8250, end: 8750 },\n { animLeaf: new Move(\"S\", 2), start: 8750, end: 9250 },\n { animLeaf: new Move(\"F\", -2), start: 8750, end: 10000 },\n { animLeaf: new Move(\"B\", 2), start: 8750, end: 10000 },\n ],\n \"M' R' U' D' M R\": [\n { animLeaf: new Move(\"M\", -1), start: 0, end: 1000 },\n { animLeaf: new Move(\"R\", -1), start: 0, end: 1000 },\n { animLeaf: new Move(\"U\", -1), start: 1000, end: 2000 },\n { animLeaf: new Move(\"D\", -1), start: 1000, end: 2000 },\n { animLeaf: new Move(\"M\"), start: 2000, end: 3000 },\n { animLeaf: new Move(\"R\"), start: 2000, end: 3000 },\n ],\n \"U' E' r E r2' E r U E\": [\n { animLeaf: new Move(\"U\", -1), start: 0, end: 1000 },\n { animLeaf: new Move(\"E\", -1), start: 0, end: 1000 },\n { animLeaf: new Move(\"r\"), start: 1000, end: 2500 },\n { animLeaf: new Move(\"E\"), start: 2500, end: 3500 },\n { animLeaf: new Move(\"r\", -2), start: 3500, end: 5000 },\n { animLeaf: new Move(\"E\"), start: 5000, end: 6000 },\n { animLeaf: new Move(\"r\"), start: 6000, end: 7000 },\n { animLeaf: new Move(\"U\"), start: 7000, end: 8000 },\n { animLeaf: new Move(\"E\"), start: 7000, end: 8000 },\n ],\n};\n\nexport class SimultaneousMoveIndexer {\n private animLeaves: AnimLeafWithRange[];\n // TODO: Allow custom `durationFn`.\n\n constructor(private kpuzzle: KPuzzle, alg: Alg) {\n this.animLeaves = demos[alg.toString()] ?? simulMoves(alg);\n // TODO: Avoid assuming all base moves are block moves.\n }\n\n public getAnimLeaf(index: number): AnimatedLeafUnit | null {\n return (\n this.animLeaves[Math.min(index, this.animLeaves.length - 1)]?.animLeaf ??\n null\n );\n }\n\n private getAnimLeafWithRange(index: number): AnimLeafWithRange {\n return this.animLeaves[Math.min(index, this.animLeaves.length - 1)];\n }\n\n public indexToMoveStartTimestamp(index: number): Timestamp {\n let start = 0;\n if (this.animLeaves.length > 0) {\n start =\n this.animLeaves[Math.min(index, this.animLeaves.length - 1)].start;\n }\n return start;\n }\n\n public timestampToIndex(timestamp: Timestamp): number {\n let i = 0;\n for (i = 0; i < this.animLeaves.length; i++) {\n if (this.animLeaves[i].start >= timestamp) {\n return Math.max(0, i - 1);\n }\n }\n return Math.max(0, i - 1);\n }\n\n public timestampToPosition(\n timestamp: Timestamp,\n startState?: KState,\n ): PuzzlePosition {\n const currentMoveInfo = this.currentMoveInfo(timestamp);\n\n let state = startState ?? this.kpuzzle.identityTransformation().toKState();\n for (const leafWithRange of this.animLeaves.slice(\n 0,\n currentMoveInfo.stateIndex,\n )) {\n const move = leafWithRange.animLeaf.as(Move);\n if (move !== null) {\n state = state.applyMove(move);\n }\n }\n\n return {\n state,\n movesInProgress: currentMoveInfo.currentMoves,\n };\n }\n\n // TODO: Caching\n public currentMoveInfo(timestamp: Timestamp): CurrentMoveInfo {\n // The starting timestamp of the earliest active move.\n let windowEarliestTimestamp = Infinity;\n for (const leafWithRange of this.animLeaves) {\n if (leafWithRange.start <= timestamp && leafWithRange.end >= timestamp) {\n windowEarliestTimestamp = Math.min(\n windowEarliestTimestamp,\n leafWithRange.start,\n );\n } else if (leafWithRange.start > timestamp) {\n break;\n }\n }\n\n const currentMoves: CurrentMove[] = [];\n const movesStarting: CurrentMove[] = [];\n const movesFinishing: CurrentMove[] = [];\n const movesFinished: CurrentMove[] = [];\n let latestStart: number = -Infinity; // TODO: is there a better way to accumulate this?\n let earliestEnd: number = Infinity; // TODO: is there a better way to accumulate this?\n\n let stateIndex: number = 0;\n for (const leafWithRange of this.animLeaves) {\n if (leafWithRange.end <= windowEarliestTimestamp) {\n stateIndex++;\n } else if (leafWithRange.start > timestamp) {\n break;\n } else {\n const move = leafWithRange.animLeaf.as(Move);\n if (move !== null) {\n let fraction =\n (timestamp - leafWithRange.start) /\n (leafWithRange.end - leafWithRange.start);\n let moveFinished = false;\n if (fraction > 1) {\n fraction = 1;\n moveFinished = true;\n }\n const currentMove = {\n move: move,\n direction: Direction.Forwards,\n fraction: fraction,\n startTimestamp: leafWithRange.start,\n endTimestamp: leafWithRange.end,\n };\n switch (fraction) {\n case 0:\n movesStarting.push(currentMove);\n break;\n case 1:\n // Generalize this to avoid reordering commuting moves.\n if (moveFinished) {\n movesFinished.push(currentMove);\n } else {\n movesFinishing.push(currentMove);\n }\n break;\n default:\n currentMoves.push(currentMove);\n latestStart = Math.max(latestStart, leafWithRange.start);\n earliestEnd = Math.min(earliestEnd, leafWithRange.end);\n }\n }\n }\n }\n return {\n stateIndex,\n currentMoves,\n latestStart,\n earliestEnd,\n movesStarting,\n movesFinishing,\n movesFinished,\n };\n }\n\n public stateAtIndex(index: number, startState?: KState): KState {\n let state = startState ?? this.kpuzzle.startState();\n for (let i = 0; i < this.animLeaves.length && i < index; i++) {\n const leafWithRange = this.animLeaves[i];\n const move = leafWithRange.animLeaf.as(Move);\n if (move !== null) {\n state = state.applyMove(move);\n }\n }\n return state;\n }\n\n public transformationAtIndex(index: number): KTransformation {\n let transformation = this.kpuzzle.identityTransformation();\n for (const leafWithRange of this.animLeaves.slice(0, index)) {\n const move = leafWithRange.animLeaf.as(Move);\n if (move !== null) {\n transformation = transformation.applyMove(move);\n }\n }\n return transformation;\n }\n\n public algDuration(): Duration {\n let max = 0;\n for (const leafWithRange of this.animLeaves) {\n max = Math.max(max, leafWithRange.end);\n }\n return max;\n }\n\n public numAnimatedLeaves(): number {\n // TODO: Cache internally once performance matters.\n return this.animLeaves.length;\n }\n\n public moveDuration(index: number): number {\n const move = this.getAnimLeafWithRange(index);\n return move.end - move.start;\n }\n}\n", "import {\n Alg,\n Commutator,\n Conjugate,\n experimentalDirectedGenerator,\n ExperimentalIterationDirection,\n Grouping,\n LineComment,\n Move,\n Newline,\n Pause,\n TraversalDownUp,\n TraversalUp,\n Unit,\n} from \"../../../../alg\";\nimport type { KPuzzle, KTransformation } from \"../../../../kpuzzle\";\nimport type { Duration } from \"../../AnimationTypes\";\nimport { AlgDuration, defaultDurationForAmount } from \"../AlgDuration\";\n\nexport class AlgPartDecoration {\n constructor(\n public moveCount: number,\n public duration: number,\n public forward: KTransformation,\n public backward: KTransformation,\n public children: Array<AlgPartDecoration> = [],\n ) {}\n}\nexport class DecoratorConstructor extends TraversalUp<AlgPartDecoration> {\n private identity: KTransformation;\n private dummyLeaf: AlgPartDecoration;\n private durationFn: TraversalUp<Duration> = new AlgDuration(\n defaultDurationForAmount,\n );\n\n private cache: { [key: string]: AlgPartDecoration } = {};\n\n constructor(private kpuzzle: KPuzzle) {\n super();\n this.identity = kpuzzle.identityTransformation();\n this.dummyLeaf = new AlgPartDecoration(\n 0,\n 0,\n this.identity,\n this.identity,\n [],\n );\n }\n\n public traverseAlg(alg: Alg): AlgPartDecoration {\n let moveCount = 0;\n let duration = 0;\n let transformation = this.identity;\n const child: Array<AlgPartDecoration> = [];\n for (const unit of alg.units()) {\n const apd = this.traverseUnit(unit);\n moveCount += apd.moveCount;\n duration += apd.duration;\n if (transformation === this.identity) {\n transformation = apd.forward;\n } else {\n transformation = transformation.applyTransformation(apd.forward);\n }\n child.push(apd);\n }\n return new AlgPartDecoration(\n moveCount,\n duration,\n transformation,\n transformation.invert(),\n child,\n );\n }\n\n public traverseGrouping(grouping: Grouping): AlgPartDecoration {\n const dec = this.traverseAlg(grouping.alg);\n return this.mult(dec, grouping.amount, [dec]);\n }\n\n public traverseMove(move: Move): AlgPartDecoration {\n const key = move.toString();\n let r: AlgPartDecoration | undefined = this.cache[key];\n if (r) {\n return r;\n }\n const transformation = this.kpuzzle.moveToTransformation(move);\n r = new AlgPartDecoration(\n 1,\n this.durationFn.traverseUnit(move),\n transformation,\n transformation.invert(),\n );\n this.cache[key] = r;\n return r;\n }\n\n public traverseCommutator(commutator: Commutator): AlgPartDecoration {\n const decA = this.traverseAlg(commutator.A);\n const decB = this.traverseAlg(commutator.B);\n const AB = decA.forward.applyTransformation(decB.forward);\n const ApBp = decA.backward.applyTransformation(decB.backward);\n const ABApBp = AB.applyTransformation(ApBp);\n const dec = new AlgPartDecoration(\n 2 * (decA.moveCount + decB.moveCount),\n 2 * (decA.duration + decB.duration),\n ABApBp,\n ABApBp.invert(),\n [decA, decB],\n );\n return this.mult(dec, 1, [dec, decA, decB]);\n }\n\n public traverseConjugate(conjugate: Conjugate): AlgPartDecoration {\n const decA = this.traverseAlg(conjugate.A);\n const decB = this.traverseAlg(conjugate.B);\n const AB = decA.forward.applyTransformation(decB.forward);\n const ABAp = AB.applyTransformation(decA.backward);\n const dec = new AlgPartDecoration(\n 2 * decA.moveCount + decB.moveCount,\n 2 * decA.duration + decB.duration,\n ABAp,\n ABAp.invert(),\n [decA, decB],\n );\n return this.mult(dec, 1, [dec, decA, decB]);\n }\n\n public traversePause(pause: Pause): AlgPartDecoration {\n return new AlgPartDecoration(\n 1,\n this.durationFn.traverseUnit(pause),\n this.identity,\n this.identity,\n );\n }\n\n public traverseNewline(_newline: Newline): AlgPartDecoration {\n return this.dummyLeaf;\n }\n\n public traverseLineComment(_comment: LineComment): AlgPartDecoration {\n return this.dummyLeaf;\n }\n\n private mult(\n apd: AlgPartDecoration,\n n: number,\n child: Array<AlgPartDecoration>,\n ): AlgPartDecoration {\n const absn = Math.abs(n);\n const st = apd.forward.selfMultiply(n);\n return new AlgPartDecoration(\n apd.moveCount * absn,\n apd.duration * absn,\n st,\n st.invert(),\n child,\n );\n }\n}\nclass WalkerDown {\n constructor(public apd: AlgPartDecoration, public back: boolean) {\n /**/\n }\n}\nexport class AlgWalker extends TraversalDownUp<WalkerDown, boolean> {\n public move?: Unit;\n public moveDuration: number;\n public back: boolean;\n public st: KTransformation;\n public root: WalkerDown;\n public i: number;\n public dur: number;\n private goali: number;\n private goaldur: number;\n constructor(\n public kpuzzle: KPuzzle,\n public algOrUnit: Alg | Unit, // TODO: can we keep these separate?\n public apd: AlgPartDecoration,\n ) {\n super();\n this.i = -1;\n this.dur = -1;\n this.goali = -1;\n this.goaldur = -1;\n this.move = undefined;\n this.back = false;\n this.moveDuration = 0;\n this.st = this.kpuzzle.identityTransformation();\n this.root = new WalkerDown(this.apd, false);\n }\n\n public moveByIndex(loc: number): boolean {\n if (this.i >= 0 && this.i === loc) {\n return this.move !== undefined;\n }\n return this.dosearch(loc, Infinity);\n }\n\n public moveByDuration(dur: number): boolean {\n if (\n this.dur >= 0 &&\n this.dur < dur &&\n this.dur + this.moveDuration >= dur\n ) {\n return this.move !== undefined;\n }\n return this.dosearch(Infinity, dur);\n }\n\n public dosearch(loc: number, dur: number): boolean {\n this.goali = loc;\n this.goaldur = dur;\n this.i = 0;\n this.dur = 0;\n this.move = undefined;\n this.moveDuration = 0;\n this.back = false;\n this.st = this.kpuzzle.identityTransformation();\n const r = this.algOrUnit.is(Alg)\n ? this.traverseAlg(this.algOrUnit as Alg, this.root)\n : this.traverseUnit(this.algOrUnit as Unit, this.root); // TODO\n return r;\n }\n\n public traverseAlg(alg: Alg, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n let i = wd.back ? alg.experimentalNumUnits() - 1 : 0;\n for (const unit of experimentalDirectedGenerator(\n alg.units(),\n wd.back\n ? ExperimentalIterationDirection.Backwards\n : ExperimentalIterationDirection.Forwards,\n )) {\n if (\n this.traverseUnit(unit, new WalkerDown(wd.apd.children[i], wd.back))\n ) {\n return true;\n }\n i += wd.back ? -1 : 1;\n }\n return false;\n }\n\n public traverseGrouping(grouping: Grouping, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n const back = this.domult(wd, grouping.amount);\n return this.traverseAlg(\n grouping.alg,\n new WalkerDown(wd.apd.children[0], back),\n );\n }\n\n public traverseMove(move: Move, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n this.move = move;\n this.moveDuration = wd.apd.duration;\n this.back = wd.back;\n return true;\n }\n\n public traverseCommutator(commutator: Commutator, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n const back = this.domult(wd, 1);\n if (back) {\n return (\n this.traverseAlg(\n commutator.B,\n new WalkerDown(wd.apd.children[2], !back),\n ) ||\n this.traverseAlg(\n commutator.A,\n new WalkerDown(wd.apd.children[1], !back),\n ) ||\n this.traverseAlg(\n commutator.B,\n new WalkerDown(wd.apd.children[2], back),\n ) ||\n this.traverseAlg(commutator.A, new WalkerDown(wd.apd.children[1], back))\n );\n } else {\n return (\n this.traverseAlg(\n commutator.A,\n new WalkerDown(wd.apd.children[1], back),\n ) ||\n this.traverseAlg(\n commutator.B,\n new WalkerDown(wd.apd.children[2], back),\n ) ||\n this.traverseAlg(\n commutator.A,\n new WalkerDown(wd.apd.children[1], !back),\n ) ||\n this.traverseAlg(\n commutator.B,\n new WalkerDown(wd.apd.children[2], !back),\n )\n );\n }\n }\n\n public traverseConjugate(conjugate: Conjugate, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n const back = this.domult(wd, 1);\n if (back) {\n return (\n this.traverseAlg(\n conjugate.A,\n new WalkerDown(wd.apd.children[1], !back),\n ) ||\n this.traverseAlg(\n conjugate.B,\n new WalkerDown(wd.apd.children[2], back),\n ) ||\n this.traverseAlg(conjugate.A, new WalkerDown(wd.apd.children[1], back))\n );\n } else {\n return (\n this.traverseAlg(\n conjugate.A,\n new WalkerDown(wd.apd.children[1], back),\n ) ||\n this.traverseAlg(\n conjugate.B,\n new WalkerDown(wd.apd.children[2], back),\n ) ||\n this.traverseAlg(conjugate.A, new WalkerDown(wd.apd.children[1], !back))\n );\n }\n }\n\n public traversePause(pause: Pause, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n this.move = pause;\n this.moveDuration = wd.apd.duration;\n this.back = wd.back;\n return true;\n }\n\n public traverseNewline(_newline: Newline, _wd: WalkerDown): boolean {\n return false;\n }\n\n public traverseLineComment(\n _lineComment: LineComment,\n _wd: WalkerDown,\n ): boolean {\n return false;\n }\n\n private firstcheck(wd: WalkerDown): boolean {\n if (\n wd.apd.moveCount + this.i <= this.goali &&\n wd.apd.duration + this.dur < this.goaldur\n ) {\n return this.keepgoing(wd);\n }\n return true;\n }\n\n private domult(wd: WalkerDown, amount: number): boolean {\n let back = wd.back;\n if (amount === 0) {\n // I don't believe this will ever happen\n return back;\n }\n if (amount < 0) {\n back = !back;\n amount = -amount;\n }\n const base = wd.apd.children[0];\n const full = Math.min(\n Math.floor((this.goali - this.i) / base.moveCount),\n Math.ceil((this.goaldur - this.dur) / base.duration - 1),\n );\n if (full > 0) {\n this.keepgoing(new WalkerDown(base, back), full);\n }\n return back;\n }\n\n private keepgoing(wd: WalkerDown, mul: number = 1): boolean {\n this.i += mul * wd.apd.moveCount;\n this.dur += mul * wd.apd.duration;\n if (mul !== 1) {\n if (wd.back) {\n this.st = this.st.applyTransformation(\n wd.apd.backward.selfMultiply(mul),\n );\n } else {\n this.st = this.st.applyTransformation(wd.apd.forward.selfMultiply(mul));\n }\n } else {\n if (wd.back) {\n this.st = this.st.applyTransformation(wd.apd.backward);\n } else {\n this.st = this.st.applyTransformation(wd.apd.forward);\n }\n }\n return false;\n }\n}\n", "import {\n Alg,\n Commutator,\n Conjugate,\n Grouping,\n LineComment,\n Move,\n Newline,\n Pause,\n TraversalUp,\n Unit,\n} from \"../../../../alg\";\nimport { AlgBuilder } from \"../../../../alg\";\n\nconst MIN_CHUNKING_THRESHOLD = 16;\n\nfunction chunkifyAlg(alg: Alg, chunkMaxLength: number): Alg {\n const mainAlgBuilder = new AlgBuilder();\n const chunkAlgBuilder = new AlgBuilder();\n for (const unit of alg.units()) {\n chunkAlgBuilder.push(unit);\n if (chunkAlgBuilder.experimentalNumUnits() >= chunkMaxLength) {\n mainAlgBuilder.push(new Grouping(chunkAlgBuilder.toAlg()));\n chunkAlgBuilder.reset();\n }\n }\n mainAlgBuilder.push(new Grouping(chunkAlgBuilder.toAlg()));\n return mainAlgBuilder.toAlg();\n}\n\nclass ChunkAlgs extends TraversalUp<Alg, Unit> {\n traverseAlg(alg: Alg): Alg {\n const algLength = alg.experimentalNumUnits();\n if (algLength < MIN_CHUNKING_THRESHOLD) {\n return alg;\n }\n return chunkifyAlg(alg, Math.ceil(Math.sqrt(algLength)));\n }\n\n traverseGrouping(grouping: Grouping): Unit {\n return new Grouping(\n this.traverseAlg(grouping.alg),\n grouping.amount, // TODO\n );\n }\n\n traverseMove(move: Move): Unit {\n return move;\n }\n\n traverseCommutator(commutator: Commutator): Unit {\n return new Conjugate(\n this.traverseAlg(commutator.A),\n this.traverseAlg(commutator.B),\n );\n }\n\n traverseConjugate(conjugate: Conjugate): Unit {\n return new Conjugate(\n this.traverseAlg(conjugate.A),\n this.traverseAlg(conjugate.B),\n );\n }\n\n traversePause(pause: Pause): Unit {\n return pause;\n }\n\n traverseNewline(newline: Newline): Unit {\n return newline;\n }\n\n traverseLineComment(comment: LineComment): Unit {\n return comment;\n }\n}\n\nconst chunkAlgsInstance = new ChunkAlgs();\nexport const chunkAlgs = chunkAlgsInstance.traverseAlg.bind(\n chunkAlgsInstance,\n) as (alg: Alg) => Alg;\n", "import type { Alg, Move } from \"../../../../alg\";\nimport type { KPuzzle, KTransformation } from \"../../../../kpuzzle\";\nimport type { KState } from \"../../../../kpuzzle/KState\";\nimport type { Duration, Timestamp } from \"../../AnimationTypes\";\nimport type { AlgIndexer } from \"../AlgIndexer\";\nimport {\n AlgPartDecoration,\n AlgWalker,\n DecoratorConstructor,\n} from \"./AlgWalker\";\nimport { chunkAlgs } from \"./chunkAlgs\";\n\nexport class TreeAlgIndexer implements AlgIndexer {\n private decoration: AlgPartDecoration;\n private walker: AlgWalker;\n constructor(private kpuzzle: KPuzzle, alg: Alg) {\n const deccon = new DecoratorConstructor(this.kpuzzle);\n\n const chunkedAlg = chunkAlgs(alg);\n\n this.decoration = deccon.traverseAlg(chunkedAlg);\n this.walker = new AlgWalker(this.kpuzzle, chunkedAlg, this.decoration);\n }\n\n public getAnimLeaf(index: number): Move | null {\n // FIXME need to support Pause\n if (this.walker.moveByIndex(index)) {\n if (!this.walker.move) {\n throw new Error(\"`this.walker.mv` missing\");\n }\n const move = this.walker.move as Move;\n // TODO: this type of negation needs to be in alg\n if (this.walker.back) {\n return move.invert();\n }\n return move;\n }\n return null;\n }\n\n public indexToMoveStartTimestamp(index: number): Timestamp {\n if (this.walker.moveByIndex(index) || this.walker.i === index) {\n return this.walker.dur;\n }\n throw new Error(`Out of algorithm: index ${index}`);\n }\n\n public indexToMovesInProgress(index: number): Timestamp {\n if (this.walker.moveByIndex(index) || this.walker.i === index) {\n return this.walker.dur;\n }\n throw new Error(`Out of algorithm: index ${index}`);\n }\n\n public stateAtIndex(index: number, startState?: KState): KState {\n this.walker.moveByIndex(index);\n return (startState ?? this.kpuzzle.startState()).applyTransformation(\n this.walker.st,\n );\n }\n\n // TransformAtIndex does not reflect the start state; it only reflects\n // the change from the start state to the current move index. If you\n // want the actual state, use stateAtIndex.\n public transformationAtIndex(index: number): KTransformation {\n this.walker.moveByIndex(index);\n return this.walker.st;\n }\n\n public numAnimatedLeaves(): number {\n return this.decoration.moveCount;\n }\n\n public timestampToIndex(timestamp: Timestamp): number {\n this.walker.moveByDuration(timestamp);\n return this.walker.i;\n }\n\n public algDuration(): Duration {\n return this.decoration.duration;\n }\n\n public moveDuration(index: number): number {\n this.walker.moveByIndex(index);\n return this.walker.moveDuration;\n }\n}\n", "import type { AlgIndexer } from \"../../../..\";\nimport type { Alg } from \"../../../../../alg\";\nimport type { KPuzzle } from \"../../../../../kpuzzle\";\nimport { experimentalCountMoves } from \"../../../../../notation\";\nimport { SimpleAlgIndexer } from \"../../../../controllers/indexer/SimpleAlgIndexer\";\nimport { SimultaneousMoveIndexer } from \"../../../../controllers/indexer/simultaneous-moves/SimultaneousMoveIndexer\";\nimport { TreeAlgIndexer } from \"../../../../controllers/indexer/tree/TreeAlgIndexer\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { VisualizationStrategy } from \"../../viewer/VisualizationStrategyProp\";\nimport type { PuzzleID } from \"../structure/PuzzleIDRequestProp\";\nimport type { AlgWithIssues } from \"./AlgProp\";\nimport type { IndexerStrategyName } from \"./IndexerConstructorRequestProp\";\n\nexport type IndexerConstructor = new (kpuzzle: KPuzzle, alg: Alg) => AlgIndexer;\n\ninterface IndexerConstructorPropInputs {\n puzzle: PuzzleID;\n alg: AlgWithIssues;\n visualizationStrategy: VisualizationStrategy;\n indexerConstructorRequest: IndexerStrategyName;\n}\n\n// TODO: Also handle PG3D vs. 3D\nexport class IndexerConstructorProp extends TwistyPropDerived<\n IndexerConstructorPropInputs,\n IndexerConstructor\n> {\n derive(inputs: IndexerConstructorPropInputs): IndexerConstructor {\n switch (inputs.indexerConstructorRequest) {\n case \"auto\":\n if (\n experimentalCountMoves(inputs.alg.alg) < 100 &&\n inputs.puzzle === \"3x3x3\" &&\n inputs.visualizationStrategy === \"Cube3D\"\n ) {\n return SimultaneousMoveIndexer;\n } else {\n return TreeAlgIndexer;\n }\n case \"tree\":\n return TreeAlgIndexer;\n case \"simple\":\n return SimpleAlgIndexer;\n case \"simultaneous\":\n return SimultaneousMoveIndexer;\n default:\n throw new Error(\"Invalid indexer request!\");\n }\n }\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport const indexerStrategyNames = {\n auto: true,\n simple: true,\n tree: true,\n simultaneous: true,\n};\nexport type IndexerStrategyName = keyof typeof indexerStrategyNames;\n\nexport class IndexerConstructorRequestProp extends SimpleTwistyPropSource<IndexerStrategyName> {\n getDefaultValue(): IndexerStrategyName {\n return \"auto\";\n }\n}\n", "import type { KPuzzle } from \"../../../../../kpuzzle\";\nimport type { AlgIndexer } from \"../../../../controllers/indexer/AlgIndexer\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { AlgWithIssues } from \"./AlgProp\";\nimport type { IndexerConstructor } from \"./IndexerConstructorProp\";\n\ntype IndexerPropInputs = {\n indexerConstructor: IndexerConstructor;\n algWithIssues: AlgWithIssues;\n kpuzzle: KPuzzle;\n};\nexport class IndexerProp extends TwistyPropDerived<\n IndexerPropInputs,\n AlgIndexer\n> {\n derive(input: IndexerPropInputs): AlgIndexer {\n return new input.indexerConstructor(input.kpuzzle, input.algWithIssues.alg);\n }\n}\n", "import type { KState } from \"../../../../../kpuzzle/KState\";\nimport type { PuzzlePosition } from \"../../../../controllers/AnimationTypes\";\nimport type { CurrentMoveInfo } from \"../../../../controllers/indexer/AlgIndexer\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\n\nexport interface LegacyPositionPropInputs {\n currentMoveInfo: CurrentMoveInfo;\n state: KState;\n}\n\n// TODO: This exist as a convenience for old `Twisty3D` implementations. Get rid of this.\nexport class LegacyPositionProp extends TwistyPropDerived<\n LegacyPositionPropInputs,\n PuzzlePosition\n> {\n derive(inputs: LegacyPositionPropInputs): PuzzlePosition {\n return {\n state: inputs.state,\n movesInProgress: inputs.currentMoveInfo.currentMoves,\n };\n }\n}\n", "import { experimentalCountMoves } from \"../../../../../notation\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { AlgWithIssues } from \"./AlgProp\";\n\ninterface NaiveMoveCountPropInputs {\n alg: AlgWithIssues;\n}\n\n// TODO: handle metrics\nexport class NaiveMoveCountProp extends TwistyPropDerived<\n NaiveMoveCountPropInputs,\n number | null\n> {\n derive(inputs: NaiveMoveCountPropInputs): number | null {\n if (inputs.alg.issues.errors.length > 0) {\n return null;\n }\n return experimentalCountMoves(inputs.alg.alg);\n }\n}\n", "import { Alg } from \"../../../../../alg\";\nimport type { KPuzzle } from \"../../../../../kpuzzle\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport { AlgIssues, AlgWithIssues } from \"./AlgProp\";\n\nlet validate: boolean = true;\nexport function experimentalSetPuzzleAlgValidation(newValidate: boolean): void {\n validate = newValidate;\n}\n\nexport class PuzzleAlgProp extends TwistyPropDerived<\n { algWithIssues: AlgWithIssues; kpuzzle: KPuzzle },\n AlgWithIssues\n> {\n async derive(inputs: {\n algWithIssues: AlgWithIssues;\n kpuzzle: KPuzzle;\n }): Promise<AlgWithIssues> {\n try {\n if (validate) {\n inputs.kpuzzle.algToTransformation(inputs.algWithIssues.alg);\n }\n\n // Looks like we could apply the alg!\n return inputs.algWithIssues;\n } catch (e) {\n return {\n alg: new Alg(),\n issues: new AlgIssues({\n errors: [`Invalid alg for puzzle: ${(e as Error).toString()}`],\n }),\n };\n }\n }\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\n// TODO: turn these maps into lists?\nexport const setupToLocations = {\n start: true, // default // TODO: \"beginning\"\n end: true,\n};\nexport type SetupToLocation = keyof typeof setupToLocations;\n\nexport class SetupAnchorProp extends SimpleTwistyPropSource<SetupToLocation> {\n getDefaultValue(): SetupToLocation {\n return \"start\";\n }\n}\n", "import type { KTransformation } from \"../../../../../kpuzzle\";\nimport { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport class SetupTransformationProp extends SimpleTwistyPropSource<KTransformation | null> {\n getDefaultValue(): KTransformation | null {\n return null;\n }\n}\n", "import type { KPuzzle } from \"../../../../../kpuzzle\";\nimport type { PuzzleLoader } from \"../../../../../puzzles\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\n\nexport class KPuzzleProp extends TwistyPropDerived<\n { puzzleLoader: PuzzleLoader },\n KPuzzle\n> {\n async derive(inputs: { puzzleLoader: PuzzleLoader }): Promise<KPuzzle> {\n return inputs.puzzleLoader.kpuzzle();\n }\n}\n", "import type { PuzzleDescriptionString } from \"../../../../../puzzle-geometry/PGPuzzles\";\nimport {\n NoValueType,\n NO_VALUE,\n SimpleTwistyPropSource,\n} from \"../../TwistyProp\";\n\nexport class PGPuzzleDescriptionStringProp extends SimpleTwistyPropSource<\n PuzzleDescriptionString | NoValueType\n> {\n getDefaultValue(): PuzzleDescriptionString | NoValueType {\n return NO_VALUE;\n }\n}\n", "import type { PuzzleLoader } from \"../../../../../puzzles\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { PuzzleID } from \"./PuzzleIDRequestProp\";\n\nexport class PuzzleIDProp extends TwistyPropDerived<\n { puzzleLoader: PuzzleLoader },\n PuzzleID\n> {\n async derive(inputs: { puzzleLoader: PuzzleLoader }): Promise<PuzzleID> {\n return inputs.puzzleLoader.id as PuzzleID;\n }\n}\n", "import {\n NoValueType,\n NO_VALUE,\n SimpleTwistyPropSource,\n} from \"../../TwistyProp\";\n\nexport const puzzleIDs = {\n \"3x3x3\": true, // default\n \"custom\": true,\n \"2x2x2\": true,\n \"4x4x4\": true,\n \"5x5x5\": true,\n \"6x6x6\": true,\n \"7x7x7\": true,\n \"40x40x40\": true,\n \"megaminx\": true,\n \"pyraminx\": true,\n \"square1\": true,\n \"clock\": true,\n \"skewb\": true,\n \"fto\": true,\n \"gigaminx\": true,\n \"master_tetraminx\": true,\n \"kilominx\": true,\n \"redi_cube\": true,\n};\nexport type PuzzleID = keyof typeof puzzleIDs;\n\n// TODO: Ideally we'd use `null` to mean \"no value\", but `null` has a special meaning\n// for `TwistyProp` and might mess with caching.\n// https://github.com/cubing/cubing.js/blob/63b0a55b83963f68410bb117a2e481052a07e086/src/cubing/twisty/model/TwistyProp.ts#L189-L189\nexport class PuzzleIDRequestProp extends SimpleTwistyPropSource<\n PuzzleID | NoValueType\n> {\n getDefaultValue(): PuzzleID | NoValueType {\n return NO_VALUE;\n }\n}\n", "import type { PuzzleDescriptionString } from \"../../../../../puzzle-geometry/PGPuzzles\";\nimport {\n cube3x3x3,\n experimentalCustomPGPuzzleLoader,\n PuzzleLoader,\n puzzles,\n} from \"../../../../../puzzles\";\nimport { NoValueType, NO_VALUE, TwistyPropDerived } from \"../../TwistyProp\";\nimport type { PuzzleID } from \"./PuzzleIDRequestProp\";\n8;\ninterface PuzzleLoaderPropInputs {\n puzzleIDRequest: PuzzleID | NoValueType;\n puzzleDescriptionRequest: PuzzleDescriptionString | NoValueType;\n}\n\nexport class PuzzleLoaderProp extends TwistyPropDerived<\n PuzzleLoaderPropInputs,\n PuzzleLoader\n> {\n derive(inputs: PuzzleLoaderPropInputs): PuzzleLoader {\n if (inputs.puzzleIDRequest && inputs.puzzleIDRequest !== NO_VALUE) {\n const puzzleLoader = puzzles[inputs.puzzleIDRequest];\n if (!puzzleLoader) {\n this.userVisibleErrorTracker!.set({\n errors: [`Invalid puzzle ID: ${inputs.puzzleIDRequest}`],\n });\n }\n return puzzleLoader;\n }\n if (\n inputs.puzzleDescriptionRequest &&\n inputs.puzzleDescriptionRequest !== NO_VALUE\n ) {\n return experimentalCustomPGPuzzleLoader(inputs.puzzleDescriptionRequest);\n }\n return cube3x3x3;\n }\n}\n", "import type { ButtonCommand } from \"../../../views/control-panel/TwistyButtons\";\nimport type { PlayingInfo } from \"./PlayingInfoProp\";\nimport type { DetailedTimelineInfo } from \"./DetailedTimelineInfoProp\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\n\ninterface ButtonAppearance {\n enabled: boolean;\n icon: string;\n title: string;\n}\nexport type ButtonAppearances = Record<ButtonCommand, ButtonAppearance>;\n\ninterface CoarseTimelineInfoInputs {\n playingInfo: PlayingInfo;\n detailedTimelineInfo: DetailedTimelineInfo;\n}\n\nexport interface CoarseTimelineInfo {\n playing: boolean;\n atStart: boolean;\n atEnd: boolean;\n}\n\n// This started as a version of `EffectiveTimestamp` without the actual\n// timestamp, to enable easier caching.\nexport class CoarseTimelineInfoProp extends TwistyPropDerived<\n CoarseTimelineInfoInputs,\n CoarseTimelineInfo\n> {\n derive(inputs: CoarseTimelineInfoInputs): CoarseTimelineInfo {\n return {\n playing: inputs.playingInfo.playing,\n atStart: inputs.detailedTimelineInfo.atStart,\n atEnd: inputs.detailedTimelineInfo.atEnd,\n };\n }\n\n canReuseValue(v1: CoarseTimelineInfo, v2: CoarseTimelineInfo): boolean {\n return (\n v1.playing === v2.playing &&\n v1.atStart === v2.atStart &&\n v1.atEnd === v2.atEnd\n );\n }\n}\n", "import type {\n MillisecondTimestamp,\n TimeRange,\n} from \"../../../controllers/AnimationTypes\";\nimport type { TimestampRequest } from \"./TimestampRequestProp\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\nimport type { SetupToLocation } from \"../puzzle/state/SetupAnchorProp\";\n\ninterface DetailedTimelineInfoInputs {\n timestampRequest: TimestampRequest;\n timeRange: TimeRange;\n setupAnchor: SetupToLocation;\n}\n\nexport interface DetailedTimelineInfo {\n timestamp: MillisecondTimestamp;\n timeRange: TimeRange; // TODO: Don't incluede this, and let fresh listeners listen to multiple inputs?\n // Note: `atStart` and `atEnd` can both be true. This is the case with the\n // default (empty) alg, which has a duration of 0 ms.\n atStart: boolean;\n atEnd: boolean;\n}\n\nexport class DetailedTimelineInfoProp extends TwistyPropDerived<\n DetailedTimelineInfoInputs,\n DetailedTimelineInfo\n> {\n derive(inputs: DetailedTimelineInfoInputs): DetailedTimelineInfo {\n let timestamp = this.#requestedTimestampToMilliseconds(inputs);\n let atStart: boolean = false;\n let atEnd: boolean = false;\n if (timestamp >= inputs.timeRange.end) {\n atEnd = true;\n timestamp = Math.min(inputs.timeRange.end, timestamp);\n }\n if (timestamp <= inputs.timeRange.start) {\n atStart = true;\n timestamp = Math.max(inputs.timeRange.start, timestamp);\n }\n return {\n timestamp,\n timeRange: inputs.timeRange,\n atStart,\n atEnd,\n };\n }\n\n #requestedTimestampToMilliseconds(\n inputs: DetailedTimelineInfoInputs,\n ): MillisecondTimestamp {\n switch (inputs.timestampRequest) {\n case \"start\":\n return inputs.timeRange.start;\n case \"end\":\n return inputs.timeRange.end;\n case \"anchor\":\n return inputs.setupAnchor === \"start\"\n ? inputs.timeRange.start\n : inputs.timeRange.end;\n case \"opposite-anchor\":\n return inputs.setupAnchor === \"start\"\n ? inputs.timeRange.end\n : inputs.timeRange.start;\n default:\n return inputs.timestampRequest;\n }\n }\n\n canReuse(v1: DetailedTimelineInfo, v2: DetailedTimelineInfo) {\n return (\n v1.timestamp === v2.timestamp &&\n v1.timeRange.start === v2.timeRange.start &&\n v1.timeRange.end === v2.timeRange.end &&\n v1.atStart === v2.atStart &&\n v1.atEnd === v2.atEnd\n );\n }\n}\n", "import { BoundaryType, Direction } from \"../../../controllers/AnimationTypes\";\nimport { TwistyPropSource } from \"../TwistyProp\";\n\nexport type SimpleDirection = Direction.Forwards | Direction.Backwards;\n\nexport interface PlayingInfo {\n playing: boolean;\n direction: SimpleDirection;\n untilBoundary: BoundaryType; // TODO: allows this to be optional in the setter?\n // TODO: Is `loop` responsible to add at this point? Maybe we should wait until we've figured out autoplay?\n // TODO: Combine `loop` into something with BoundaryType?\n loop: boolean;\n}\n\n// TODO: direction,\nexport class PlayingInfoProp extends TwistyPropSource<\n PlayingInfo,\n Partial<PlayingInfo>\n> {\n async getDefaultValue(): Promise<PlayingInfo> {\n return {\n direction: Direction.Forwards,\n playing: false,\n untilBoundary: BoundaryType.EntireTimeline,\n loop: false,\n };\n }\n\n async derive(\n newInfo: Partial<PlayingInfo>,\n oldValuePromise: Promise<PlayingInfo>,\n ): Promise<PlayingInfo> {\n const oldValue = await oldValuePromise;\n\n const newValue: PlayingInfo = Object.assign({}, oldValue);\n Object.assign(newValue, newInfo);\n return newValue;\n }\n\n canReuseValue(v1: PlayingInfo, v2: PlayingInfo) {\n return (\n v1.direction === v2.direction &&\n v1.playing === v2.playing &&\n v1.untilBoundary === v2.untilBoundary &&\n v1.loop === v2.loop\n );\n }\n}\n", "import { TwistyPropSource } from \"../TwistyProp\";\n\n// TODO: Pick a better name. `speed` is probably good, although that could mean\n// something else (e.g. shorter, faster moves but still with the same spacing).\nexport class TempoScaleProp extends TwistyPropSource<number, number> {\n getDefaultValue(): number {\n return 1;\n }\n\n derive(v: number): number {\n return v < 0 ? 1 : v;\n }\n}\n", "import type { MillisecondTimestamp } from \"../../../controllers/AnimationTypes\";\nimport { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nconst smartTimestamps = {\n \"start\": true,\n \"end\": true,\n \"anchor\": true,\n \"opposite-anchor\": true,\n};\n\nexport type TimestampRequest =\n | MillisecondTimestamp\n | keyof typeof smartTimestamps;\n\nexport class TimestampRequestProp extends SimpleTwistyPropSource<TimestampRequest> {\n getDefaultValue(): TimestampRequest {\n return \"opposite-anchor\";\n }\n\n // TODO: Support `Promise`\n set(v: TimestampRequest) {\n if (!this.validInput(v)) {\n // TODO: Generalize this to more props. How do we surface this? Throw an error and catch it from sync setters that call into this?\n return;\n }\n super.set(v);\n }\n\n validInput(v: TimestampRequest): boolean {\n if (typeof v === \"number\") {\n return true;\n }\n if (smartTimestamps[v]) {\n return true;\n }\n return false;\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nexport const backViewLayouts = {\n \"none\": true, // default\n \"side-by-side\": true,\n \"top-right\": true,\n};\nexport type BackViewLayout = keyof typeof backViewLayouts;\n\nexport type BackViewLayoutWithAuto = BackViewLayout | \"auto\";\n\nexport class BackViewProp extends SimpleTwistyPropSource<BackViewLayoutWithAuto> {\n getDefaultValue(): BackViewLayoutWithAuto {\n return \"auto\";\n }\n}\n", "import type { TimeRange } from \"../../../controllers/AnimationTypes\";\nimport type { AlgIndexer } from \"../../../controllers/indexer/AlgIndexer\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\n\nexport class TimeRangeProp extends TwistyPropDerived<\n { indexer: AlgIndexer },\n TimeRange\n> {\n derive(inputs: { indexer: AlgIndexer }): TimeRange {\n return {\n start: 0,\n end: inputs.indexer.algDuration(),\n };\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nexport const viewerLinkPages = {\n \"twizzle\": true, // default\n \"experimental-twizzle-explorer\": true,\n \"none\": true,\n};\nexport type ViewerLinkPage = keyof typeof viewerLinkPages;\nexport type ViewerLinkPageWithAuto = ViewerLinkPage | \"auto\";\n\nexport class ViewerLinkProp extends SimpleTwistyPropSource<ViewerLinkPageWithAuto> {\n getDefaultValue(): ViewerLinkPageWithAuto {\n return \"auto\";\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\n// TODO: turn these maps into lists?\nexport const visualizationFormats = {\n \"3D\": true, // default\n \"2D\": true,\n \"experimental-2D-LL\": true, // TODO\n \"PG3D\": true,\n};\nexport type VisualizationFormat = keyof typeof visualizationFormats;\nexport type VisualizationFormatWithAuto = VisualizationFormat | \"auto\";\n\nexport class VisualizationFormatProp extends SimpleTwistyPropSource<VisualizationFormatWithAuto> {\n getDefaultValue(): VisualizationFormatWithAuto {\n return \"auto\";\n }\n}\n", "import type { VisualizationFormatWithAuto } from \"./VisualizationProp\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\nimport type { PuzzleID } from \"../../..\";\n\ntype VisualizationStrategyPropInputs = {\n visualizationRequest: VisualizationFormatWithAuto;\n puzzleID: PuzzleID;\n};\n\nexport type VisualizationStrategy =\n | \"Cube3D\"\n | \"2D\"\n | \"experimental-2D-LL\"\n | \"PG3D\";\n\nexport class VisualizationStrategyProp extends TwistyPropDerived<\n VisualizationStrategyPropInputs,\n VisualizationStrategy\n> {\n derive(inputs: VisualizationStrategyPropInputs): VisualizationStrategy {\n switch (inputs.puzzleID) {\n case \"clock\":\n case \"square1\":\n case \"kilominx\":\n case \"redi_cube\":\n return \"2D\";\n case \"3x3x3\":\n switch (inputs.visualizationRequest) {\n case \"auto\":\n case \"3D\":\n return \"Cube3D\";\n default:\n return inputs.visualizationRequest;\n }\n default:\n switch (inputs.visualizationRequest) {\n case \"auto\":\n case \"3D\":\n return \"PG3D\";\n case \"experimental-2D-LL\":\n return \"2D\";\n default:\n return inputs.visualizationRequest;\n }\n }\n }\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport type FoundationDisplay = \"auto\" | \"opaque\" | \"none\";\n\nexport class FoundationDisplayProp extends SimpleTwistyPropSource<FoundationDisplay> {\n getDefaultValue(): FoundationDisplay {\n return \"auto\";\n }\n}\n", "import type { Texture, TextureLoader } from \"three\";\nimport { THREEJS } from \"../../../../heavy-code-imports/3d\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\n\nlet cachedLoader: TextureLoader | null = null;\nasync function loader(): Promise<TextureLoader> {\n return (cachedLoader ??= new (await THREEJS).TextureLoader());\n}\n\ntype SpritePropInputs = {\n spriteURL: URL | null;\n};\n\n// TODO: Find a way to make the 3D elements own this, instead of the main `TwistyPlayerModel`.\nexport class SpriteProp extends TwistyPropDerived<\n SpritePropInputs,\n Texture | null\n> {\n async derive(inputs: SpritePropInputs): Promise<Texture | null> {\n const { spriteURL: textureURL } = inputs;\n if (textureURL === null) {\n return null;\n }\n // eslint-disable-next-line no-async-promise-executor\n return new Promise(async (resolve, _reject) => {\n const onLoadingError = (): void => {\n console.warn(\"Could not load sprite:\", textureURL.toString());\n resolve(null);\n };\n // TODO: provide a way to listen for errors?\n try {\n (await loader()).load(\n textureURL.toString(),\n resolve,\n onLoadingError,\n onLoadingError,\n );\n } catch (e) {\n onLoadingError();\n }\n });\n }\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport const dragInputModes = {\n auto: true,\n none: true,\n};\nexport type DragInputMode = keyof typeof dragInputModes;\n\nexport class DragInputProp extends SimpleTwistyPropSource<DragInputMode> {\n getDefaultValue(): DragInputMode {\n return \"auto\";\n }\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport const movePressInputNames = {\n auto: true,\n none: true,\n basic: true,\n};\nexport type MovePressInput = keyof typeof movePressInputNames;\n\nexport class MovePressInputProp extends SimpleTwistyPropSource<MovePressInput> {\n getDefaultValue(): MovePressInput {\n return \"auto\";\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nexport const backgroundThemes = {\n checkered: true, // default\n none: true,\n};\nexport type BackgroundTheme = keyof typeof backgroundThemes;\n\nexport type BackgroundThemeWithAuto = BackgroundTheme | \"auto\";\n\nexport class BackgroundProp extends SimpleTwistyPropSource<BackgroundThemeWithAuto> {\n getDefaultValue(): BackgroundThemeWithAuto {\n return \"auto\";\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\nimport type { CoordinateDegrees } from \"./OrbitCoordinatesRequestProp\";\n\n// Similar to https://alg.cubing.net/\nconst DEFAULT_LATITUDE_LIMIT = 35;\n\nexport class LatitudeLimitProp extends SimpleTwistyPropSource<CoordinateDegrees> {\n getDefaultValue(): CoordinateDegrees {\n return DEFAULT_LATITUDE_LIMIT;\n }\n}\n", "import { mod } from \"../../helpers\";\nimport { TwistyPropSource } from \"../TwistyProp\";\n\nexport type CoordinateDegrees = number;\n\nexport interface OrbitCoordinates {\n latitude: CoordinateDegrees;\n longitude: CoordinateDegrees;\n distance: number;\n}\n\nexport function orbitCoordinatesEqual(\n c1: OrbitCoordinates,\n c2: OrbitCoordinates,\n): boolean {\n return (\n c1.latitude === c2.latitude &&\n c1.longitude === c2.longitude &&\n c1.distance === c2.distance\n );\n}\n\n// TOOD: Check if freezing affects perf.\n// const DEFAULT_COORDINATES = Object.freeze({\n// latitude: 35,\n// longitude: 30,\n// distance: 6,\n// });\n\nexport type OrbitCoordinatesRequest = Partial<OrbitCoordinates> | \"auto\";\n\n// TODO: Put the \"auto\" calculations in a separate place.\nexport class OrbitCoordinatesRequestProp extends TwistyPropSource<\n OrbitCoordinatesRequest,\n Partial<OrbitCoordinates> | \"auto\"\n> {\n getDefaultValue(): OrbitCoordinatesRequest {\n return \"auto\";\n }\n\n canReuseValue(v1: OrbitCoordinates, v2: OrbitCoordinates) {\n return v1 === v2 || orbitCoordinatesEqual(v1, v2);\n }\n\n async derive(\n newCoordinates: Partial<OrbitCoordinates> | \"auto\",\n oldValuePromise: Promise<OrbitCoordinatesRequest>,\n ): Promise<OrbitCoordinatesRequest> {\n if (newCoordinates === \"auto\") {\n return \"auto\";\n }\n\n let oldValue = await oldValuePromise;\n if (oldValue === \"auto\") {\n oldValue = {};\n }\n\n const newValue: Partial<OrbitCoordinates> = Object.assign({}, oldValue);\n Object.assign(newValue, newCoordinates);\n\n if (typeof newValue.latitude !== \"undefined\") {\n newValue.latitude = Math.min(Math.max(newValue.latitude, -90), 90);\n }\n if (typeof newValue.longitude !== \"undefined\") {\n newValue.longitude = mod(newValue.longitude, 360, 180);\n }\n return newValue;\n }\n}\n", "import { DEGREES_PER_RADIAN } from \"../../../views/3D/TAU\";\nimport type { PuzzleID } from \"../puzzle/structure/PuzzleIDRequestProp\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\nimport {\n CoordinateDegrees,\n OrbitCoordinates,\n orbitCoordinatesEqual,\n OrbitCoordinatesRequest,\n} from \"./OrbitCoordinatesRequestProp\";\nimport type { VisualizationStrategy } from \"./VisualizationStrategyProp\";\n\ninterface OrbitCoordinatesPropInputs {\n orbitCoordinatesRequest: OrbitCoordinatesRequest;\n latitudeLimit: CoordinateDegrees;\n puzzleID: PuzzleID;\n strategy: VisualizationStrategy;\n}\n\nexport class OrbitCoordinatesProp extends TwistyPropDerived<\n OrbitCoordinatesPropInputs,\n OrbitCoordinates\n> {\n canReuseValue(v1: OrbitCoordinates, v2: OrbitCoordinates) {\n return orbitCoordinatesEqual(v1, v2);\n }\n\n async derive(inputs: OrbitCoordinatesPropInputs): Promise<OrbitCoordinates> {\n if (inputs.orbitCoordinatesRequest === \"auto\") {\n return defaultCameraOrbitCoordinates(inputs.puzzleID, inputs.strategy);\n }\n\n const req: OrbitCoordinates = Object.assign(\n Object.assign(\n {},\n defaultCameraOrbitCoordinates(inputs.puzzleID, inputs.strategy),\n inputs.orbitCoordinatesRequest,\n ),\n );\n\n if (Math.abs(req.latitude) <= inputs.latitudeLimit) {\n return req;\n } else {\n const { latitude, longitude, distance } = req;\n // TODO: Should we re-normalize the request, so we don't depend on normalization in the input?\n return {\n latitude: inputs.latitudeLimit * Math.sign(latitude),\n longitude,\n distance,\n };\n }\n }\n}\n\n// const DEFAULT_CAMERA_Z = 5;\n// // Golden ratio is perfect for FTO and Megaminx.\n// const DEFAULT_CAMERA_Y = DEFAULT_CAMERA_Z * (2 / (1 + Math.sqrt(5)));\nexport const centeredCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: 31.717474411461005,\n longitude: 0,\n distance: 5.877852522924731,\n};\n\n// This is tuned so that the hint facelets for 3x3x3 always fit in the canvas.\nexport const cubeCube3DCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: 35,\n longitude: 30,\n distance: 6,\n};\n\n// This is tuned so that the hint facelets always fit in the canvas.\nexport const cubePG3DCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: 35,\n longitude: 30,\n distance: 6.25,\n};\n\nexport const megaminxCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: Math.atan(1 / 2) * DEGREES_PER_RADIAN,\n longitude: 0,\n distance: 6.7,\n};\n\nexport const pyraminxCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: 26.56505117707799,\n longitude: 0,\n distance: 6,\n};\n\nexport const cornerCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: 35.264389682754654,\n longitude: 45,\n distance: 6.928203230275509,\n};\n\n// TODO\nexport function defaultCameraOrbitCoordinates(\n puzzleID: PuzzleID,\n strategy: VisualizationStrategy,\n): OrbitCoordinates {\n if (puzzleID[1] === \"x\") {\n if (strategy === \"Cube3D\") {\n return cubeCube3DCameraOrbitCoordinates;\n } else {\n return cubePG3DCameraOrbitCoordinates;\n }\n } else {\n switch (puzzleID) {\n case \"megaminx\":\n case \"gigaminx\":\n return megaminxCameraOrbitCoordinates;\n case \"pyraminx\":\n case \"master_tetraminx\":\n return pyraminxCameraOrbitCoordinates;\n case \"skewb\":\n return cubePG3DCameraOrbitCoordinates;\n default:\n return centeredCameraOrbitCoordinates;\n }\n }\n}\n// TODO: templatize\nexport interface ManagedAttribute<K> {\n string: string;\n value: K;\n setString(s: string): boolean;\n setValue(v: K): boolean;\n}\n", "import { URLProp } from \"./props/general/URLProp\";\nimport { FoundationDisplayProp } from \"./props/puzzle/display/FoundationDisplayProp\";\nimport { HintFaceletProp } from \"./props/puzzle/display/HintFaceletProp\";\nimport { SpriteProp } from \"./props/puzzle/display/SpriteProp\";\nimport { StickeringProp } from \"./props/puzzle/display/StickeringProp\";\nimport { DragInputProp } from \"./props/puzzle/state/DragInputProp\";\nimport { MovePressInputProp } from \"./props/puzzle/state/MovePressInputProp\";\nimport { BackgroundProp } from \"./props/viewer/BackgroundProp\";\nimport { LatitudeLimitProp } from \"./props/viewer/LatitudeLimit\";\nimport { OrbitCoordinatesProp } from \"./props/viewer/OrbitCoordinatesProp\";\nimport { OrbitCoordinatesRequestProp } from \"./props/viewer/OrbitCoordinatesRequestProp\";\nimport type { TwistyPlayerModel } from \"./TwistyPlayerModel\";\n\nexport class TwistySceneModel {\n // Depth 0\n background = new BackgroundProp();\n dragInput = new DragInputProp();\n foundationDisplay = new FoundationDisplayProp();\n foundationStickerSpriteURL = new URLProp();\n hintFacelet = new HintFaceletProp();\n hintStickerSpriteURL = new URLProp();\n latitudeLimit = new LatitudeLimitProp();\n movePressInput = new MovePressInputProp();\n orbitCoordinatesRequest: OrbitCoordinatesRequestProp =\n new OrbitCoordinatesRequestProp();\n stickering = new StickeringProp();\n\n // Depth 1\n foundationStickerSprite = new SpriteProp({\n spriteURL: this.foundationStickerSpriteURL,\n });\n\n hintStickerSprite = new SpriteProp({\n spriteURL: this.hintStickerSpriteURL,\n });\n\n // Depth 4\n orbitCoordinates: OrbitCoordinatesProp;\n\n constructor(public twistyPlayerModel: TwistyPlayerModel) {\n this.orbitCoordinates = new OrbitCoordinatesProp({\n orbitCoordinatesRequest: this.orbitCoordinatesRequest,\n latitudeLimit: this.latitudeLimit,\n puzzleID: twistyPlayerModel.puzzleID,\n strategy: twistyPlayerModel.visualizationStrategy,\n });\n }\n}\n", "import { arrayEquals } from \"./helpers\";\nimport { SimpleTwistyPropSource } from \"./props/TwistyProp\";\n\ninterface UserVisibleError {\n errors: string[];\n}\n\nconst EMPTY_ERRORS = { errors: [] };\n\nexport class UserVisibleErrorTracker extends SimpleTwistyPropSource<UserVisibleError> {\n override getDefaultValue(): UserVisibleError {\n return EMPTY_ERRORS;\n }\n\n reset() {\n this.set(this.getDefaultValue());\n }\n\n canReuseValue(_v1: UserVisibleError, _v2: UserVisibleError): boolean {\n return arrayEquals(_v1.errors, _v2.errors);\n }\n}\n", "import { experimentalAppendMove, Move } from \"../../alg\";\nimport { ArbitraryStringProp } from \"./props/general/ArbitraryStringProp\";\nimport { URLProp } from \"./props/general/URLProp\";\nimport { AlgProp } from \"./props/puzzle/state/AlgProp\";\nimport { AlgTransformationProp } from \"./props/puzzle/state/AlgTransformationProp\";\nimport { AnchorTransformationProp } from \"./props/puzzle/state/AnchorTransformationProp\";\nimport { CatchUpMoveProp } from \"./props/puzzle/state/CatchUpMoveProp\";\nimport { CurrentLeavesSimplifiedProp } from \"./props/puzzle/state/CurrentLeavesSimplified\";\nimport { CurrentMoveInfoProp } from \"./props/puzzle/state/CurrentMoveInfoProp\";\nimport { CurrentStateProp as CurrentStateProp } from \"./props/puzzle/state/CurrentStateProp\";\nimport { IndexerConstructorProp } from \"./props/puzzle/state/IndexerConstructorProp\";\nimport { IndexerConstructorRequestProp } from \"./props/puzzle/state/IndexerConstructorRequestProp\";\nimport { IndexerProp } from \"./props/puzzle/state/IndexerProp\";\nimport { LegacyPositionProp } from \"./props/puzzle/state/LegacyPositionProp\";\nimport { NaiveMoveCountProp } from \"./props/puzzle/state/NaiveMoveCountProp\";\nimport { PuzzleAlgProp } from \"./props/puzzle/state/PuzzleAlgProp\";\nimport { SetupAnchorProp } from \"./props/puzzle/state/SetupAnchorProp\";\nimport { SetupTransformationProp } from \"./props/puzzle/state/SetupTransformationProp\";\nimport { KPuzzleProp } from \"./props/puzzle/structure/KPuzzleProp\";\nimport { PGPuzzleDescriptionStringProp } from \"./props/puzzle/structure/PuzzleDescriptionProp\";\nimport { PuzzleIDProp } from \"./props/puzzle/structure/PuzzleIDProp\";\nimport { PuzzleIDRequestProp } from \"./props/puzzle/structure/PuzzleIDRequestProp\";\nimport { PuzzleLoaderProp } from \"./props/puzzle/structure/PuzzleLoaderProp\";\nimport { CoarseTimelineInfoProp } from \"./props/timeline/CoarseTimelineInfoProp\";\nimport { DetailedTimelineInfoProp } from \"./props/timeline/DetailedTimelineInfoProp\";\nimport { PlayingInfoProp } from \"./props/timeline/PlayingInfoProp\";\nimport { TempoScaleProp } from \"./props/timeline/TempoScaleProp\";\nimport { TimestampRequestProp } from \"./props/timeline/TimestampRequestProp\";\nimport { NO_VALUE } from \"./props/TwistyProp\";\nimport { BackViewProp } from \"./props/viewer/BackViewProp\";\nimport { ButtonAppearanceProp } from \"./props/viewer/ButtonAppearanceProp\";\nimport { ControlPanelProp } from \"./props/viewer/ControlPanelProp\";\nimport { TimeRangeProp } from \"./props/viewer/TimeRangeProp\";\nimport { ViewerLinkProp } from \"./props/viewer/ViewerLinkProp\";\nimport { VisualizationFormatProp } from \"./props/viewer/VisualizationProp\";\nimport { VisualizationStrategyProp } from \"./props/viewer/VisualizationStrategyProp\";\nimport { TwistySceneModel } from \"./TwistySceneModel\";\nimport { UserVisibleErrorTracker } from \"./UserVisibleErrorTracker\";\n\nexport class TwistyPlayerModel {\n // TODO: incorporate error handling into the entire prop graph.\n // TODO: Make this something that can't get confused with normal props?\n userVisibleErrorTracker = new UserVisibleErrorTracker();\n\n // TODO: Redistribute and group props with controllers.\n\n // Depth 0\n alg = new AlgProp();\n backView = new BackViewProp();\n controlPanel = new ControlPanelProp();\n catchUpMove = new CatchUpMoveProp();\n indexerConstructorRequest = new IndexerConstructorRequestProp();\n playingInfo = new PlayingInfoProp();\n puzzleDescriptionRequest = new PGPuzzleDescriptionStringProp();\n puzzleIDRequest = new PuzzleIDRequestProp();\n setupAnchor = new SetupAnchorProp();\n setupAlg = new AlgProp();\n setupTransformation = new SetupTransformationProp();\n tempoScale = new TempoScaleProp();\n timestampRequest = new TimestampRequestProp();\n viewerLink = new ViewerLinkProp();\n visualizationFormat = new VisualizationFormatProp();\n // Metadata\n title = new ArbitraryStringProp();\n videoURL = new URLProp();\n competitionID = new ArbitraryStringProp();\n\n // Depth 1\n puzzleLoader = new PuzzleLoaderProp(\n {\n puzzleIDRequest: this.puzzleIDRequest,\n puzzleDescriptionRequest: this.puzzleDescriptionRequest,\n },\n this.userVisibleErrorTracker,\n );\n\n // Depth 2\n kpuzzle = new KPuzzleProp({ puzzleLoader: this.puzzleLoader });\n\n puzzleID = new PuzzleIDProp({ puzzleLoader: this.puzzleLoader });\n\n // Depth 3\n\n puzzleAlg = new PuzzleAlgProp({\n algWithIssues: this.alg,\n kpuzzle: this.kpuzzle,\n });\n\n puzzleSetupAlg = new PuzzleAlgProp({\n algWithIssues: this.setupAlg,\n kpuzzle: this.kpuzzle,\n });\n\n visualizationStrategy = new VisualizationStrategyProp({\n visualizationRequest: this.visualizationFormat,\n puzzleID: this.puzzleID,\n });\n\n // Depth 4\n indexerConstructor = new IndexerConstructorProp({\n alg: this.alg,\n puzzle: this.puzzleID,\n visualizationStrategy: this.visualizationStrategy,\n indexerConstructorRequest: this.indexerConstructorRequest,\n });\n\n moveCount = new NaiveMoveCountProp({ alg: this.puzzleAlg });\n\n setupAlgTransformation = new AlgTransformationProp({\n setupAlg: this.puzzleSetupAlg,\n kpuzzle: this.kpuzzle,\n });\n\n // Depth 5\n indexer = new IndexerProp({\n indexerConstructor: this.indexerConstructor,\n algWithIssues: this.puzzleAlg,\n kpuzzle: this.kpuzzle,\n });\n\n // Depth 6\n anchorTransformation = new AnchorTransformationProp({\n setupTransformation: this.setupTransformation,\n setupAnchor: this.setupAnchor,\n setupAlgTransformation: this.setupAlgTransformation,\n indexer: this.indexer,\n });\n\n timeRange = new TimeRangeProp({\n indexer: this.indexer,\n });\n\n // Depth 7\n detailedTimelineInfo: DetailedTimelineInfoProp = new DetailedTimelineInfoProp(\n {\n timestampRequest: this.timestampRequest,\n timeRange: this.timeRange,\n setupAnchor: this.setupAnchor,\n },\n );\n\n // Depth 8\n coarseTimelineInfo = new CoarseTimelineInfoProp({\n detailedTimelineInfo: this.detailedTimelineInfo,\n playingInfo: this.playingInfo,\n });\n\n currentMoveInfo = new CurrentMoveInfoProp({\n indexer: this.indexer,\n detailedTimelineInfo: this.detailedTimelineInfo,\n catchUpMove: this.catchUpMove,\n });\n\n // Depth 9\n // TODO: Inline Twisty3D management.\n buttonAppearance = new ButtonAppearanceProp({\n coarseTimelineInfo: this.coarseTimelineInfo,\n viewerLink: this.viewerLink,\n });\n\n currentLeavesSimplified = new CurrentLeavesSimplifiedProp({\n currentMoveInfo: this.currentMoveInfo,\n });\n\n // Depth 10\n currentState = new CurrentStateProp({\n anchoredStart: this.anchorTransformation,\n currentLeavesSimplified: this.currentLeavesSimplified,\n indexer: this.indexer,\n });\n\n // Depth 11\n legacyPosition = new LegacyPositionProp({\n currentMoveInfo: this.currentMoveInfo,\n state: this.currentState,\n });\n\n twistySceneModel = new TwistySceneModel(this);\n\n public async twizzleLink(): Promise<string> {\n const [\n viewerLink,\n puzzleID,\n puzzleDescription,\n alg,\n setup,\n anchor,\n experimentalStickering,\n ] = await Promise.all([\n this.viewerLink.get(),\n this.puzzleID.get(),\n this.puzzleDescriptionRequest.get(),\n this.alg.get(),\n this.setupAlg.get(),\n this.setupAnchor.get(),\n this.twistySceneModel.stickering.get(),\n ]);\n\n const isExplorer = viewerLink === \"experimental-twizzle-explorer\";\n\n console.log({ isExplorer, viewerLink });\n\n const url = new URL(\n `https://alpha.twizzle.net/${isExplorer ? \"explore\" : \"edit\"}/`,\n );\n\n if (!alg.alg.experimentalIsEmpty()) {\n url.searchParams.set(\"alg\", alg.alg.toString());\n }\n if (!setup.alg.experimentalIsEmpty()) {\n url.searchParams.set(\"setup-alg\", setup.alg.toString());\n }\n if (anchor !== \"start\") {\n url.searchParams.set(\"setup-anchor\", anchor);\n }\n if (experimentalStickering !== \"full\") {\n url.searchParams.set(\"experimental-stickering\", experimentalStickering);\n }\n if (isExplorer && puzzleDescription !== NO_VALUE) {\n url.searchParams.set(\"puzzle-description\", puzzleDescription);\n } else if (puzzleID !== \"3x3x3\") {\n url.searchParams.set(\"puzzle\", puzzleID);\n }\n return url.toString();\n }\n\n // TODO: Animate the new move.\n experimentalAddMove(\n flexibleMove: Move | string,\n options: { coalesce?: boolean; mod?: number } = {},\n ): void {\n const move =\n typeof flexibleMove === \"string\" ? new Move(flexibleMove) : flexibleMove;\n (async () => {\n const alg = (await this.alg.get()).alg;\n const newAlg = experimentalAppendMove(alg, move, {\n coalesce: options?.coalesce,\n mod: options?.mod,\n });\n this.alg.set(newAlg);\n this.timestampRequest.set(\"end\");\n this.catchUpMove.set({\n move: move,\n amount: 0,\n });\n })();\n }\n\n // TODO: Remove after https://github.com/Odder/pyraminx.tips/pull/1 lands\n /** @deprecated */\n get playingInfoProp(): PlayingInfoProp {\n console.warn(\n \"Using deprecated prop: `playingInfoProp`. Please switch to: `playingInfo`\",\n );\n return this.playingInfo;\n }\n}\n", "import type { Alg } from \"../../alg\";\nimport type { PuzzleDescriptionString } from \"../../puzzle-geometry/PGPuzzles\";\nimport type { ExperimentalStickering, PuzzleID } from \"../../twisty\";\nimport type { BackgroundThemeWithAuto } from \"../model/props/viewer/BackgroundProp\";\nimport type { BackViewLayoutWithAuto } from \"../model/props/viewer/BackViewProp\";\nimport type { ControlPanelThemeWithAuto } from \"../model/props/viewer/ControlPanelProp\";\nimport type { HintFaceletStyleWithAuto } from \"../model/props/puzzle/display/HintFaceletProp\";\nimport type { IndexerStrategyName } from \"../model/props/puzzle/state/IndexerConstructorRequestProp\";\nimport type { TimestampRequest } from \"../model/props/timeline/TimestampRequestProp\";\nimport type { ViewerLinkPageWithAuto } from \"../model/props/viewer/ViewerLinkProp\";\nimport type { VisualizationFormatWithAuto } from \"../model/props/viewer/VisualizationProp\";\nimport { TwistyPlayerModel } from \"../model/TwistyPlayerModel\";\nimport type { MillisecondTimestamp } from \"../controllers/AnimationTypes\";\nimport { ManagedCustomElement } from \"./ManagedCustomElement\";\nimport type { MovePressInput } from \"../model/props/puzzle/state/MovePressInputProp\";\nimport type { SetupToLocation } from \"../model/props/puzzle/state/SetupAnchorProp\";\nimport type { DragInputMode } from \"../model/props/puzzle/state/DragInputProp\";\n\nfunction err(propName: string): Error {\n return new Error(\n `Cannot get \\`.${propName}\\` directly from a \\`TwistyPlayer\\`.`,\n );\n}\n\n// prettier-ignore\nexport abstract class TwistyPlayerSettable extends ManagedCustomElement {\n experimentalModel: TwistyPlayerModel = new TwistyPlayerModel();\n\n set alg(newAlg: Alg | string) { this.experimentalModel.alg.set(newAlg); }\n get alg(): never { throw err(\"alg\"); }\n\n set experimentalSetupAlg(newSetup: Alg | string) { this.experimentalModel.setupAlg.set(newSetup); }\n get experimentalSetupAlg(): never { throw err(\"setup\"); }\n\n set experimentalSetupAnchor(anchor: SetupToLocation) { this.experimentalModel.setupAnchor.set(anchor); }\n get experimentalSetupAnchor(): never { throw err(\"anchor\"); }\n\n set puzzle(puzzleID: PuzzleID) { this.experimentalModel.puzzleIDRequest.set(puzzleID); }\n get puzzle(): never { throw err(\"puzzle\"); }\n\n set experimentalPuzzleDescription(puzzleDescription: PuzzleDescriptionString) { this.experimentalModel.puzzleDescriptionRequest.set(puzzleDescription); }\n get experimentalPuzzleDescription(): never { throw err(\"experimentalPuzzleDescription\"); }\n\n set timestamp(timestamp: TimestampRequest) { this.experimentalModel.timestampRequest.set(timestamp); }\n get timestamp(): never { throw err(\"timestamp\"); }\n\n set hintFacelets(hintFaceletStyle: HintFaceletStyleWithAuto) { this.experimentalModel.twistySceneModel.hintFacelet.set(hintFaceletStyle); }\n get hintFacelets(): never { throw err(\"hintFacelets\"); }\n\n set experimentalStickering(stickering: ExperimentalStickering) { this.experimentalModel.twistySceneModel.stickering.set(stickering); }\n get experimentalStickering(): never { throw err(\"stickering\"); }\n\n set backView(backView: BackViewLayoutWithAuto) { this.experimentalModel.backView.set(backView); }\n get backView(): never { throw err(\"backView\"); }\n\n set background(backgroundTheme: BackgroundThemeWithAuto) { this.experimentalModel.twistySceneModel.background.set(backgroundTheme); }\n get background(): never { throw err(\"background\"); }\n\n set controlPanel(newControlPanel: ControlPanelThemeWithAuto) { this.experimentalModel.controlPanel.set(newControlPanel); }\n get controlPanel(): never { throw err(\"controlPanel\"); }\n\n set visualization(visualizationFormat: VisualizationFormatWithAuto) { this.experimentalModel.visualizationFormat.set(visualizationFormat); }\n get visualization(): never { throw err(\"visualization\"); }\n\n set experimentalTitle(title: string | null) { this.experimentalModel.title.set(title); }\n get experimentalTitle(): never { throw err(\"experimentalTitle\"); }\n\n set experimentalVideoURL(videoURL: string | null) { this.experimentalModel.videoURL.set(videoURL); }\n get experimentalVideoURL(): never { throw err(\"experimentalVideoURL\"); }\n\n set experimentalCompetitionID(competitionID: string | null) { this.experimentalModel.competitionID.set(competitionID); }\n get experimentalCompetitionID(): never { throw err(\"experimentalCompetitionID\"); }\n\n set viewerLink(viewerLinkPage: ViewerLinkPageWithAuto) { this.experimentalModel.viewerLink.set(viewerLinkPage); }\n get viewerLink(): never { throw err(\"viewerLink\"); }\n\n set experimentalMovePressInput(movePressInput: MovePressInput) { this.experimentalModel.twistySceneModel.movePressInput.set(movePressInput); }\n get experimentalMovePressInput(): never { throw err(\"experimentalMovePressInput\"); }\n\n set cameraLatitude(latitude: number) { this.experimentalModel.twistySceneModel.orbitCoordinatesRequest.set({ latitude }); }\n get cameraLatitude(): never { throw err(\"cameraLatitude\"); }\n\n set cameraLongitude(longitude: number) { this.experimentalModel.twistySceneModel.orbitCoordinatesRequest.set({ longitude }); }\n get cameraLongitude(): never { throw err(\"cameraLongitude\"); }\n\n set cameraDistance(distance: number) { this.experimentalModel.twistySceneModel.orbitCoordinatesRequest.set({ distance }); }\n get cameraDistance(): never { throw err(\"cameraDistance\"); }\n\n set cameraLatitudeLimit(latitudeLimit: number) { this.experimentalModel.twistySceneModel.latitudeLimit.set(latitudeLimit); }\n get cameraLatitudeLimit(): never { throw err(\"cameraLatitudeLimit\"); }\n\n set indexer(indexer: IndexerStrategyName) { this.experimentalModel.indexerConstructorRequest.set(indexer); }\n get indexer(): never { throw err(\"indexer\"); }\n\n set tempoScale(newTempoScale: number) { this.experimentalModel.tempoScale.set(newTempoScale); }\n get tempoScale(): never { throw err(\"tempoScale\"); }\n\n set experimentalSprite(url: string | URL) { this.experimentalModel.twistySceneModel.foundationStickerSpriteURL.set(url); }\n get experimentalSprite(): never { throw err(\"experimentalSprite\"); }\n\n set experimentalHintSprite(url: string | URL) { this.experimentalModel.twistySceneModel.hintStickerSpriteURL.set(url); }\n get experimentalHintSprite(): never { throw err(\"experimentalHintSprite\"); }\n\n set experimentalDragInput(dragInputMode: DragInputMode) { this.experimentalModel.twistySceneModel.dragInput.set(dragInputMode); }\n get experimentalDragInput(): never { throw err(\"experimentalDragInput\"); }\n\n experimentalGet = new ExperimentalGetters(this.experimentalModel)\n}\n\nclass ExperimentalGetters {\n constructor(private model: TwistyPlayerModel) {}\n\n async alg(): Promise<Alg> {\n return (await this.model.alg.get()).alg;\n }\n\n async setupAlg(): Promise<Alg> {\n return (await this.model.setupAlg.get()).alg;\n }\n\n puzzleID(): Promise<PuzzleID> {\n return this.model.puzzleID.get();\n }\n\n async timestamp(): Promise<MillisecondTimestamp> {\n return (await this.model.detailedTimelineInfo.get()).timestamp;\n }\n}\n", "import type { ExperimentalStickering } from \"..\";\nimport type { Alg, Move } from \"../../alg\";\nimport type { PuzzleDescriptionString } from \"../../puzzle-geometry/PGPuzzles\";\nimport type { TwistyAnimationControllerDelegate } from \"../controllers/TwistyAnimationController\";\nimport { TwistyPlayerController } from \"../controllers/TwistyPlayerController\";\nimport type { HintFaceletStyleWithAuto } from \"../model/props/puzzle/display/HintFaceletProp\";\nimport type { DragInputMode } from \"../model/props/puzzle/state/DragInputProp\";\nimport type { MovePressInput } from \"../model/props/puzzle/state/MovePressInputProp\";\nimport type { SetupToLocation } from \"../model/props/puzzle/state/SetupAnchorProp\";\nimport type { PuzzleID } from \"../model/props/puzzle/structure/PuzzleIDRequestProp\";\nimport type { BackgroundThemeWithAuto } from \"../model/props/viewer/BackgroundProp\";\nimport type { BackViewLayoutWithAuto } from \"../model/props/viewer/BackViewProp\";\nimport {\n ControlPanelThemeWithAuto,\n controlsLocations,\n} from \"../model/props/viewer/ControlPanelProp\";\nimport type { ViewerLinkPageWithAuto } from \"../model/props/viewer/ViewerLinkProp\";\nimport type { VisualizationFormatWithAuto } from \"../model/props/viewer/VisualizationProp\";\nimport type { VisualizationStrategy } from \"../model/props/viewer/VisualizationStrategyProp\";\nimport { Twisty2DSceneWrapper } from \"./2D/Twisty2DSceneWrapper\";\nimport type { PG3D } from \"./3D/puzzles/PG3D\";\nimport { Twisty3DSceneWrapper } from \"./3D/Twisty3DSceneWrapper\";\nimport { ClassListManager } from \"./ClassListManager\";\nimport { TwistyButtons } from \"./control-panel/TwistyButtons\";\nimport { TwistyScrubber } from \"./control-panel/TwistyScrubber\";\nimport { customElementsShim } from \"./node-custom-element-shims\";\nimport { downloadURL, getDefaultFilename, screenshot } from \"./screenshot\";\nimport { twistyPlayerCSS } from \"./TwistyPlayer.css\";\nimport { TwistyPlayerSettable } from \"./TwistyPlayerSettable\";\n\nconst DATA_ATTRIBUTE_PREFIX = \"data-\";\n\n// TODO: I couldn't figure out how to use use more specific types. Ideally, we'd\n// enforce consistency with the model.\nexport const twistyPlayerAttributeMap = {\n // TODO: We assume each of these can be set using a string or will be automatically converted by JS (e.g. numbers). Can we enforce\n // that with types? Do we need to add a translation mechanism for things we\n // don't want to leave settable as strings?\n // TODO: Enum validation.\n\n // Alg\n \"alg\": \"alg\",\n \"experimental-setup-alg\": \"experimentalSetupAlg\",\n\n // String-based\n \"experimental-setup-anchor\": \"experimentalSetupAnchor\",\n \"puzzle\": \"puzzle\",\n \"experimental-puzzle-description\": \"experimentalPuzzleDescription\",\n \"visualization\": \"visualization\",\n \"hint-facelets\": \"hintFacelets\",\n \"experimental-stickering\": \"experimentalStickering\",\n \"background\": \"background\",\n \"control-panel\": \"controlPanel\",\n \"back-view\": \"backView\",\n // \"indexer\": \"indexer\",\n \"viewer-link\": \"viewerLink\",\n \"experimental-move-press-input\": \"experimentalMovePressInput\",\n \"experimental-drag-input\": \"experimentalDragInput\",\n\n // Metadata\n \"experimental-title\": \"experimentalTitle\",\n \"experimental-video-url\": \"experimentalVideoURL\",\n \"experimental-competition-id\": \"experimentalCompetitionID\",\n\n // Number-based\n \"camera-latitude\": \"cameraLatitude\",\n \"camera-longitude\": \"cameraLongitude\",\n \"camera-distance\": \"cameraDistance\",\n \"camera-latitude-limit\": \"cameraLatitudeLimit\",\n \"tempo-scale\": \"tempoScale\",\n\n // URL-based\n \"experimental-sprite\": \"experimentalSprite\",\n \"experimental-hint-sprite\": \"experimentalHintSprite\",\n};\n\nexport type TwistyPlayerAttribute = keyof typeof twistyPlayerAttributeMap;\n\nconst configKeys: Record<TwistyPlayerAttribute, true> = Object.fromEntries(\n Object.values(twistyPlayerAttributeMap).map((s) => [s, true]),\n) as any;\n\n// TODO: Find a way to share this def with `attributeMap`.\nexport interface TwistyPlayerConfig {\n // Alg\n alg?: Alg | string;\n experimentalSetupAlg?: Alg | string;\n\n // String-based\n experimentalSetupAnchor?: SetupToLocation; // TODO: \"auto\"\n puzzle?: PuzzleID;\n experimentalPuzzleDescription?: PuzzleDescriptionString;\n visualization?: VisualizationFormatWithAuto;\n hintFacelets?: HintFaceletStyleWithAuto;\n experimentalStickering?: ExperimentalStickering;\n background?: BackViewLayoutWithAuto;\n controlPanel?: ControlPanelThemeWithAuto;\n backView?: BackViewLayoutWithAuto;\n // \"indexer\"?: \"indexer\";\n viewerLink?: ViewerLinkPageWithAuto;\n experimentalMovePressInput?: MovePressInput;\n experimentalDragInput?: DragInputMode;\n\n // Metadata\n experimentalTitle?: string | null;\n experimentalVideoURL?: string;\n experimentalCompetitionID?: string;\n\n // Number-based\n cameraLatitude?: number;\n cameraLongitude?: number;\n cameraDistance?: number;\n cameraLatitudeLimit?: number;\n tempoScale?: number;\n\n // URL-based\n experimentalSprite?: string | null;\n experimentalHintSprite?: string | null;\n}\n\n/**\n * TwistyPlayer is the heart of `cubing.js`. It can be used to display a puzzle on a web page like this:\n *\n * <script src=\"path/to/cubing/twisty\" type=\"module\"></script>\n * <twisty-player alg=\"R U R'\"></twisty-player>\n *\n * You can also construct it directly in JavaScript:\n *\n * import { TwistyPlayer } from \"cubing/twisty\";\n * const twistyPlayer = new TwistyPlayer({alg: \"R U R'\"});\n * // Once the page has loaded, you can do this:\n * document.body.appendChild(twistyPlayer);\n *\n * See {@link https://js.cubing.net/cubing/} for more examples.\n */\nexport class TwistyPlayer\n extends TwistyPlayerSettable\n implements TwistyAnimationControllerDelegate\n{\n controller: TwistyPlayerController = new TwistyPlayerController(\n this.experimentalModel,\n this,\n );\n\n buttons: TwistyButtons;\n\n experimentalCanvasClickCallback: (...args: any) => void = () => {};\n // #onCanvasClick() {\n\n // }\n\n constructor(config: TwistyPlayerConfig = {}) {\n super();\n\n // TODO: double-check that these are all getting set sync without causing extra work.\n for (const [propName, value] of Object.entries(config)) {\n if (!configKeys[propName as TwistyPlayerAttribute]) {\n console.warn(`Invalid config passed to TwistyPlayer: ${propName}`);\n break;\n }\n (this as any)[propName] = value;\n }\n }\n\n #controlsManager: ClassListManager<ControlPanelThemeWithAuto> =\n new ClassListManager<ControlPanelThemeWithAuto>(\n this,\n \"controls-\",\n ([\"auto\"] as ControlPanelThemeWithAuto[]).concat(\n Object.keys(controlsLocations) as ControlPanelThemeWithAuto[],\n ),\n );\n\n #visualizationWrapperElem = document.createElement(\"div\"); // TODO: Better pattern.\n #errorElem = document.createElement(\"div\"); // TODO: Better pattern.\n #alreadyConnected = false; // TODO: support resetting\n async connectedCallback(): Promise<void> {\n if (this.#alreadyConnected) {\n return;\n }\n this.#alreadyConnected = true;\n this.addCSS(twistyPlayerCSS);\n\n this.addElement(this.#visualizationWrapperElem).classList.add(\n \"visualization-wrapper\",\n );\n this.addElement(this.#errorElem).classList.add(\"error-elem\");\n this.#errorElem.textContent = \"Error\";\n this.experimentalModel.userVisibleErrorTracker.addFreshListener(\n (userVisibleError) => {\n const errorString: string | null = userVisibleError.errors[0] ?? null;\n this.contentWrapper.classList.toggle(\"error\", !!errorString);\n if (errorString) {\n this.#errorElem.textContent = errorString;\n }\n },\n );\n\n const scrubber = new TwistyScrubber(this.experimentalModel);\n this.contentWrapper.appendChild(scrubber);\n\n this.buttons = new TwistyButtons(\n this.experimentalModel,\n this.controller,\n this,\n );\n this.contentWrapper.appendChild(this.buttons);\n\n this.experimentalModel.twistySceneModel.background.addFreshListener(\n (backgroundTheme: BackgroundThemeWithAuto) => {\n this.contentWrapper.classList.toggle(\n \"checkered\",\n backgroundTheme !== \"none\",\n );\n },\n );\n\n this.experimentalModel.controlPanel.addFreshListener(\n (controlPanel: ControlPanelThemeWithAuto) => {\n this.#controlsManager.setValue(controlPanel);\n },\n );\n\n this.experimentalModel.visualizationStrategy.addFreshListener(\n this.#setVisualizationWrapper.bind(this),\n );\n\n this.experimentalModel.puzzleID.addFreshListener(this.flash.bind(this));\n }\n\n #flashLevel: \"auto\" | \"none\" = \"auto\";\n /** @deprecated */\n experimentalSetFlashLevel(newLevel: \"auto\" | \"none\"): void {\n this.#flashLevel = newLevel;\n }\n\n flash() {\n if (this.#flashLevel === \"auto\") {\n this.#visualizationWrapper?.animate([{ opacity: 0.25 }, { opacity: 1 }], {\n duration: 250,\n easing: \"ease-out\",\n });\n }\n }\n\n #visualizationWrapper: Twisty2DSceneWrapper | Twisty3DSceneWrapper | null =\n null;\n\n #visualizationStrategy: VisualizationStrategy | null = null;\n #setVisualizationWrapper(strategy: VisualizationStrategy): void {\n if (strategy !== this.#visualizationStrategy) {\n this.#visualizationWrapper?.remove();\n this.#visualizationWrapper?.disconnect();\n let newWrapper: Twisty2DSceneWrapper | Twisty3DSceneWrapper;\n switch (strategy) {\n case \"2D\":\n case \"experimental-2D-LL\":\n newWrapper = new Twisty2DSceneWrapper(\n this.experimentalModel.twistySceneModel,\n strategy,\n );\n break;\n case \"Cube3D\":\n case \"PG3D\":\n // TODO: Properly wire this up so we can set PG3D for the cube.\n newWrapper = new Twisty3DSceneWrapper(this.experimentalModel);\n break;\n default:\n throw new Error(\"Invalid visualization\");\n }\n this.#visualizationWrapperElem.appendChild(newWrapper);\n this.#visualizationWrapper = newWrapper;\n this.#visualizationStrategy = strategy;\n }\n }\n\n async experimentalCurrentCanvases(): Promise<HTMLCanvasElement[]> {\n this.connectedCallback();\n const wrapper = this.#visualizationWrapper;\n const canvases: HTMLCanvasElement[] = [];\n if (wrapper instanceof Twisty3DSceneWrapper) {\n const vantages = wrapper.experimentalVantages();\n for (const vantage of vantages) {\n canvases.push((await vantage.canvasInfo()).canvas);\n }\n }\n return canvases;\n }\n\n async experimentalPG3D(): Promise<PG3D | null> {\n this.connectedCallback();\n const wrapper = this.#visualizationWrapper;\n if (wrapper instanceof Twisty3DSceneWrapper) {\n wrapper;\n }\n return null;\n }\n\n jumpToStart(options?: { flash: boolean }): void {\n this.controller.jumpToStart(options);\n }\n\n jumpToEnd(options?: { flash: boolean }): void {\n this.controller.jumpToEnd(options);\n }\n\n play(): void {\n this.controller.togglePlay(true);\n }\n\n pause(): void {\n this.controller.togglePlay(false);\n }\n\n // Inspiration:\n // - https://developer.mozilla.org/en-US/docs/Web/API/Element/toggleAttribute (`force` argument)\n // - https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle (`force` argument)\n // We still provide `play()` and `pause()` individually for convenience, though.\n togglePlay(play?: boolean): void {\n this.controller.togglePlay(play);\n }\n\n // TODO: Animate the new move.\n experimentalAddMove(\n flexibleMove: Move | string,\n options: { coalesce?: boolean } = {},\n ): void {\n this.experimentalModel.experimentalAddMove(flexibleMove, options);\n }\n\n static get observedAttributes(): string[] {\n const observed = [];\n for (const key of Object.keys(twistyPlayerAttributeMap)) {\n observed.push(key, DATA_ATTRIBUTE_PREFIX + key);\n }\n return observed;\n }\n\n attributeChangedCallback(\n attributeName: string,\n _oldValue: string,\n newValue: string,\n ): void {\n if (attributeName.startsWith(\"data-\")) {\n attributeName = attributeName.slice(\"data-\".length);\n }\n const setterName =\n twistyPlayerAttributeMap[attributeName as TwistyPlayerAttribute];\n if (!setterName) {\n return;\n }\n\n (this as any)[setterName] = newValue;\n }\n\n // TODO: Make this more ergonomic and flexible.\n // TODO: dimensions.\n async experimentalScreenshot(options?: {\n width: number;\n height: number;\n }): Promise<string> {\n return (await screenshot(this.experimentalModel, options)).dataURL;\n }\n\n // TODO: Make this more ergonomic and flexible.\n // TODO: dimensions.\n async experimentalDownloadScreenshot(filename?: string): Promise<void> {\n if (\n [\"2D\", \"experimental-2D-LL\"].includes(\n await this.experimentalModel.visualizationStrategy.get(),\n )\n ) {\n // TODO: This has lots of async issues. It should also go into the screenshot impl file.\n const wrapper2D = this.#visualizationWrapper as Twisty2DSceneWrapper;\n const twisty2DPuzzle = await wrapper2D\n .currentTwisty2DPuzzleWrapper()!\n .twisty2DPuzzle();\n const str = new XMLSerializer().serializeToString(\n twisty2DPuzzle.svg.element,\n );\n const url = URL.createObjectURL(new Blob([str]));\n downloadURL(\n url,\n filename ?? (await getDefaultFilename(this.experimentalModel)),\n \"svg\",\n );\n } else {\n await (await screenshot(this.experimentalModel)).download(filename);\n }\n }\n}\n\ncustomElementsShim.define(\"twisty-player\", TwistyPlayer);\ndeclare global {\n interface HTMLElementTagNameMap {\n \"twisty-player\": TwistyPlayer;\n }\n}\n", "import { CSSSource } from \"./ManagedCustomElement\";\n\nexport const twistyAlgViewerCSS = new CSSSource(`\n:host {\n display: inline-grid;\n}\n\na:not(:hover) {\n color: inherit;\n text-decoration: none;\n}\n\ntwisty-alg-leaf-elem.twisty-alg-comment {\n color: rgba(0, 0, 0, 0.4);\n}\n\n.wrapper.current-move {\n background: rgba(66, 133, 244, 0.3);\n margin-left: -0.1em;\n margin-right: -0.1em;\n padding-left: 0.1em;\n padding-right: 0.1em;\n border-radius: 0.1em;\n}\n`);\n", "import {\n Alg,\n Commutator,\n Conjugate,\n experimentalDirect,\n ExperimentalIterationDirection,\n Grouping,\n LineComment,\n Move,\n Newline,\n Pause,\n TraversalDownUp,\n Unit,\n} from \"../../alg\";\nimport type { Parsed } from \"../../alg/parse\";\nimport type { AlgWithIssues } from \"../model/props/puzzle/state/AlgProp\";\nimport type { DetailedTimelineInfo } from \"../model/props/timeline/DetailedTimelineInfoProp\";\nimport type { MillisecondTimestamp } from \"../controllers/AnimationTypes\";\nimport type { CurrentMoveInfo } from \"../controllers/indexer/AlgIndexer\";\nimport { ManagedCustomElement } from \"./ManagedCustomElement\";\nimport {\n customElementsShim,\n HTMLElementShim,\n} from \"./node-custom-element-shims\";\nimport { twistyAlgViewerCSS } from \"./TwistyAlgViewer.css\";\nimport { TwistyPlayer } from \"./TwistyPlayer\";\n\nconst DEFAULT_OFFSET_MS = 250; // TODO: make this a fraction?\n\nclass DataDown {\n earliestMoveIndex: number;\n twistyAlgViewer: TwistyAlgViewer;\n direction: ExperimentalIterationDirection;\n}\n\nclass DataUp {\n moveCount: number;\n element: TwistyAlgWrapperElem | TwistyAlgLeafElem;\n}\n\nclass TwistyAlgLeafElem extends ManagedCustomElement {\n constructor(\n className: string,\n text: string,\n dataDown: DataDown,\n public algOrUnit: Alg | Unit,\n offsetIntoMove: boolean,\n clickable: boolean,\n ) {\n super({ mode: \"open\" });\n this.classList.add(className);\n\n this.addCSS(twistyAlgViewerCSS);\n if (clickable) {\n const anchor = this.contentWrapper.appendChild(\n document.createElement(\"a\"),\n );\n anchor.href = \"#\";\n anchor.textContent = text;\n\n anchor.addEventListener(\"click\", (e) => {\n e.preventDefault();\n dataDown.twistyAlgViewer.jumpToIndex(\n dataDown.earliestMoveIndex,\n offsetIntoMove,\n );\n });\n } else {\n this.contentWrapper.appendChild(\n document.createElement(\"span\"),\n ).textContent = text;\n }\n }\n\n pathToIndex(_index: number): (TwistyAlgWrapperElem | TwistyAlgLeafElem)[] {\n return [];\n }\n\n setCurrentMove(current: boolean) {\n this.contentWrapper.classList.toggle(\"current-move\", current);\n }\n}\n\ncustomElementsShim.define(\"twisty-alg-leaf-elem\", TwistyAlgLeafElem);\n\nclass TwistyAlgWrapperElem extends HTMLElementShim {\n private queue: (Element | Text)[] = [];\n\n constructor(className: string, public algOrUnit: Alg | Unit) {\n super();\n this.classList.add(className);\n }\n\n addString(str: string) {\n this.queue.push(document.createTextNode(str));\n }\n\n addElem(dataUp: DataUp): number {\n this.queue.push(dataUp.element);\n return dataUp.moveCount;\n }\n\n flushQueue(\n direction: ExperimentalIterationDirection = ExperimentalIterationDirection.Forwards,\n ): void {\n for (const node of maybeReverseList(this.queue, direction)) {\n this.append(node);\n }\n this.queue = [];\n }\n\n pathToIndex(_index: number): (TwistyAlgWrapperElem | TwistyAlgLeafElem)[] {\n return [];\n }\n}\n\ncustomElementsShim.define(\"twisty-alg-wrapper-elem\", TwistyAlgWrapperElem);\n\nfunction oppositeDirection(\n direction: ExperimentalIterationDirection,\n): ExperimentalIterationDirection {\n return direction === ExperimentalIterationDirection.Forwards\n ? ExperimentalIterationDirection.Backwards\n : ExperimentalIterationDirection.Forwards;\n}\n\nfunction updateDirectionByAmount(\n currentDirection: ExperimentalIterationDirection,\n amount: number,\n): ExperimentalIterationDirection {\n return amount < 0 ? oppositeDirection(currentDirection) : currentDirection;\n}\n\nfunction maybeReverseList<T>(\n l: T[],\n direction: ExperimentalIterationDirection,\n): T[] {\n if (direction === ExperimentalIterationDirection.Forwards) {\n return l;\n }\n // console.log(\"rev\", Array.from(l).reverse());\n // return Array.from(l).reverse();\n const copy = Array.from(l);\n copy.reverse();\n return copy;\n}\n\nclass AlgToDOMTree extends TraversalDownUp<DataDown, DataUp, DataUp> {\n public traverseAlg(alg: Alg, dataDown: DataDown): DataUp {\n let moveCount = 0;\n const element = new TwistyAlgWrapperElem(\"twisty-alg-alg\", alg); // TODO: pick a better class name.\n let first = true;\n for (const unit of experimentalDirect(alg.units(), dataDown.direction)) {\n if (!first) {\n element.addString(\" \");\n }\n first = false;\n moveCount += element.addElem(\n this.traverseUnit(unit, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction: dataDown.direction,\n }),\n );\n }\n element.flushQueue(dataDown.direction);\n return {\n moveCount: moveCount,\n element,\n };\n }\n\n public traverseGrouping(grouping: Grouping, dataDown: DataDown): DataUp {\n const square1Tuple = grouping.experimentalAsSquare1Tuple();\n // if (square1Tuplle) {\n\n // }\n\n const direction = updateDirectionByAmount(\n dataDown.direction,\n grouping.amount,\n );\n let moveCount = 0;\n const element = new TwistyAlgWrapperElem(\"twisty-alg-grouping\", grouping);\n element.addString(\"(\");\n\n if (square1Tuple) {\n moveCount += element.addElem({\n moveCount: 1,\n element: new TwistyAlgLeafElem(\n \"twisty-alg-move\", // TODO: Mark the tuple with a special class?\n square1Tuple[0].amount.toString(),\n dataDown,\n square1Tuple[0],\n true,\n true,\n ),\n });\n element.addString(\", \");\n moveCount += element.addElem({\n moveCount: 1,\n element: new TwistyAlgLeafElem(\n \"twisty-alg-move\", // TODO: Mark the tuple with a special class?\n square1Tuple[1].amount.toString(),\n dataDown,\n square1Tuple[1],\n true,\n true,\n ),\n });\n } else {\n moveCount += element.addElem(\n this.traverseAlg(grouping.alg, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction,\n }),\n );\n }\n\n element.addString(\")\" + grouping.experimentalRepetitionSuffix);\n element.flushQueue();\n return {\n moveCount: moveCount * Math.abs(grouping.amount),\n element,\n };\n }\n\n public traverseMove(move: Move, dataDown: DataDown): DataUp {\n const element = new TwistyAlgLeafElem(\n \"twisty-alg-move\",\n move.toString(),\n dataDown,\n move,\n true,\n true,\n );\n dataDown.twistyAlgViewer.highlighter.addMove(\n (move as Parsed<Move>).startCharIndex,\n element,\n );\n return {\n moveCount: 1,\n element,\n };\n }\n\n public traverseCommutator(\n commutator: Commutator,\n dataDown: DataDown,\n ): DataUp {\n let moveCount = 0;\n const element = new TwistyAlgWrapperElem(\n \"twisty-alg-commutator\",\n commutator,\n );\n element.addString(\"[\");\n element.flushQueue();\n const [first, second]: Alg[] = maybeReverseList(\n [commutator.A, commutator.B],\n dataDown.direction,\n );\n moveCount += element.addElem(\n this.traverseAlg(first, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction: dataDown.direction,\n }),\n );\n element.addString(\", \");\n moveCount += element.addElem(\n this.traverseAlg(second, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction: dataDown.direction,\n }),\n );\n element.flushQueue(dataDown.direction);\n element.addString(\"]\");\n element.flushQueue();\n return {\n moveCount: moveCount * 2,\n element,\n };\n }\n\n public traverseConjugate(conjugate: Conjugate, dataDown: DataDown): DataUp {\n let moveCount = 0;\n const element = new TwistyAlgWrapperElem(\"twisty-alg-conjugate\", conjugate);\n element.addString(\"[\");\n const aLen = element.addElem(\n this.traverseAlg(conjugate.A, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction: dataDown.direction,\n }),\n );\n moveCount += aLen;\n element.addString(\": \");\n moveCount += element.addElem(\n this.traverseAlg(conjugate.B, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction: dataDown.direction,\n }),\n );\n element.addString(\"]\");\n element.flushQueue();\n return {\n moveCount: moveCount + aLen,\n element,\n };\n }\n\n public traversePause(pause: Pause, dataDown: DataDown): DataUp {\n return {\n moveCount: 1,\n element: new TwistyAlgLeafElem(\n \"twisty-alg-pause\",\n \".\",\n dataDown,\n pause,\n true,\n true,\n ),\n };\n }\n\n public traverseNewline(newline: Newline, _dataDown: DataDown): DataUp {\n const element = new TwistyAlgWrapperElem(\"twisty-alg-newline\", newline);\n element.append(document.createElement(\"br\"));\n return {\n moveCount: 0,\n element,\n };\n }\n\n public traverseLineComment(\n lineComment: LineComment,\n dataDown: DataDown,\n ): DataUp {\n return {\n moveCount: 0,\n element: new TwistyAlgLeafElem(\n \"twisty-alg-line-comment\",\n `//${lineComment.text}`,\n dataDown,\n lineComment,\n false,\n false,\n ),\n };\n }\n}\n\nconst algToDOMTreeInstance = new AlgToDOMTree();\nconst algToDOMTree = algToDOMTreeInstance.traverseAlg.bind(\n algToDOMTreeInstance,\n) as (alg: Alg, dataDown: DataDown) => DataUp;\n\nclass MoveHighlighter {\n moveCharIndexMap: Map<number, TwistyAlgLeafElem> = new Map();\n currentElem: TwistyAlgLeafElem | null = null;\n\n addMove(charIndex: number, elem: TwistyAlgLeafElem): void {\n this.moveCharIndexMap.set(charIndex, elem);\n }\n\n set(move: Parsed<Move> | null): void {\n const newElem = move\n ? this.moveCharIndexMap.get(move.startCharIndex) ?? null\n : null;\n if (this.currentElem === newElem) {\n return;\n }\n this.currentElem?.classList.remove(\"twisty-alg-current-move\");\n this.currentElem?.setCurrentMove(false);\n newElem?.classList.add(\"twisty-alg-current-move\");\n newElem?.setCurrentMove(true);\n this.currentElem = newElem;\n }\n}\n\nexport class TwistyAlgViewer extends HTMLElementShim {\n highlighter: MoveHighlighter = new MoveHighlighter();\n #domTree: TwistyAlgWrapperElem | TwistyAlgLeafElem;\n #twistyPlayer: TwistyPlayer | null = null;\n lastClickTimestamp: number | null = null;\n constructor(options?: { twistyPlayer?: TwistyPlayer }) {\n super();\n if (options?.twistyPlayer) {\n this.twistyPlayer = options?.twistyPlayer;\n }\n }\n\n protected connectedCallback(): void {\n // nothing to do?\n }\n\n private setAlg(alg: Alg): void {\n this.#domTree = algToDOMTree(alg, {\n earliestMoveIndex: 0,\n twistyAlgViewer: this,\n direction: ExperimentalIterationDirection.Forwards,\n }).element;\n this.textContent = \"\";\n this.appendChild(this.#domTree);\n }\n\n get twistyPlayer(): TwistyPlayer | null {\n return this.#twistyPlayer;\n }\n\n set twistyPlayer(twistyPlayer: TwistyPlayer | null) {\n this.#setTwistyPlayer(twistyPlayer);\n }\n\n async #setTwistyPlayer(twistyPlayer: TwistyPlayer | null) {\n if (this.#twistyPlayer) {\n console.warn(\"twisty-player reassignment is not supported\");\n return;\n }\n if (twistyPlayer === null) {\n throw new Error(\"clearing twistyPlayer is not supported\");\n }\n this.#twistyPlayer = twistyPlayer;\n\n this.#twistyPlayer.experimentalModel.alg.addFreshListener(\n (algWithIssues: AlgWithIssues) => {\n this.setAlg(algWithIssues.alg);\n },\n );\n\n const sourceAlg = (await this.#twistyPlayer.experimentalModel.alg.get())\n .alg;\n // TODO: Use proper architecture instead of a heuristic to ensure we have a parsed alg annotated with char indices.\n const parsedAlg =\n \"startCharIndex\" in (sourceAlg as Partial<Parsed<Alg>>)\n ? sourceAlg\n : Alg.fromString(sourceAlg.toString());\n this.setAlg(parsedAlg);\n\n twistyPlayer.experimentalModel.currentMoveInfo.addFreshListener(\n (currentMoveInfo: CurrentMoveInfo) => {\n let moveInfo = currentMoveInfo.currentMoves[0];\n moveInfo ??= currentMoveInfo.movesStarting[0];\n moveInfo ??= currentMoveInfo.movesFinishing[0];\n if (!moveInfo) {\n this.highlighter.set(null);\n } else {\n const mainCurrentMove = moveInfo.move; // TODO\n this.highlighter.set(mainCurrentMove as Parsed<Move>);\n }\n },\n );\n\n twistyPlayer.experimentalModel.detailedTimelineInfo.addFreshListener(\n (detailedTimelineInfo: DetailedTimelineInfo) => {\n if (detailedTimelineInfo.timestamp !== this.lastClickTimestamp) {\n this.lastClickTimestamp = null;\n }\n },\n );\n }\n\n async jumpToIndex(index: number, offsetIntoMove: boolean): Promise<void> {\n // TODO: Fix async issues.\n const twistyPlayer = this.#twistyPlayer;\n if (twistyPlayer) {\n twistyPlayer.pause();\n const timestampPromise = (async (): Promise<MillisecondTimestamp> => {\n const indexer = await twistyPlayer.experimentalModel.indexer.get();\n const offset = offsetIntoMove ? DEFAULT_OFFSET_MS : 0;\n return (indexer.indexToMoveStartTimestamp(index) ?? -offset) + offset;\n })();\n twistyPlayer.experimentalModel.timestampRequest.set(\n await timestampPromise, // TODO\n );\n if (this.lastClickTimestamp === (await timestampPromise)) {\n twistyPlayer.play();\n this.lastClickTimestamp = null;\n } else {\n this.lastClickTimestamp = await timestampPromise;\n }\n }\n }\n\n protected async attributeChangedCallback(\n attributeName: string,\n _oldValue: string,\n newValue: string,\n ): Promise<void> {\n if (attributeName === \"for\") {\n const elem = document.getElementById(newValue);\n if (!elem) {\n console.warn(\"for= elem does not exist\");\n return;\n }\n await customElements.whenDefined(\"twisty-player\");\n if (!(elem instanceof TwistyPlayer)) {\n console.warn(\"for= elem is not a twisty-player\");\n return;\n }\n this.twistyPlayer = elem;\n }\n }\n\n static get observedAttributes(): string[] {\n return [\"for\"];\n }\n}\n\ncustomElementsShim.define(\"twisty-alg-viewer\", TwistyAlgViewer);\ndeclare global {\n interface HTMLElementTagNameMap {\n \"twisty-alg-viewer\": TwistyAlgViewer;\n }\n}\n", "import {\n Alg,\n Commutator,\n Conjugate,\n Grouping,\n LineComment,\n Move,\n Newline,\n Pause,\n TraversalDownUp,\n} from \"../../../alg\";\nimport type { Parsed } from \"../../../alg/parse\";\nimport type { AnimatedLeafUnit } from \"../../controllers/indexer/simultaneous-moves/simul-moves\";\n\nexport type AnimatedLeafUnitInfo = {\n leaf: Parsed<AnimatedLeafUnit>;\n idx: number;\n};\nexport type OrderedLeafTokens = AnimatedLeafUnitInfo[];\n\ninterface DataUp {\n tokens: OrderedLeafTokens;\n numLeavesInside: number;\n}\n\ninterface DataDown {\n numMovesSofar: number;\n}\n\nclass LeafTokens extends TraversalDownUp<DataDown, DataUp> {\n public traverseAlg(alg: Alg, dataDown: DataDown): DataUp {\n const unitArrays: OrderedLeafTokens[] = [];\n let numMovesInside = 0;\n for (const unit of alg.units()) {\n const dataUp = this.traverseUnit(unit, {\n numMovesSofar: dataDown.numMovesSofar + numMovesInside,\n });\n unitArrays.push(dataUp.tokens);\n numMovesInside += dataUp.numLeavesInside;\n }\n return {\n tokens: Array.prototype.concat(...unitArrays),\n numLeavesInside: numMovesInside,\n };\n }\n\n public traverseGrouping(grouping: Grouping, dataDown: DataDown): DataUp {\n const dataUp = this.traverseAlg(grouping.alg, dataDown);\n return {\n tokens: dataUp.tokens,\n numLeavesInside: dataUp.numLeavesInside * grouping.amount,\n };\n }\n\n public traverseMove(move: Move, dataDown: DataDown): DataUp {\n return {\n tokens: [{ leaf: move as Parsed<Move>, idx: dataDown.numMovesSofar }],\n numLeavesInside: 1,\n }; // TODO: What if not parsed?\n }\n\n public traverseCommutator(\n commutator: Commutator,\n dataDown: DataDown,\n ): DataUp {\n const dataUpA = this.traverseAlg(commutator.A, dataDown);\n const dataUpB = this.traverseAlg(commutator.B, {\n numMovesSofar: dataDown.numMovesSofar + dataUpA.numLeavesInside,\n });\n return {\n tokens: dataUpA.tokens.concat(dataUpB.tokens),\n numLeavesInside: dataUpA.numLeavesInside * 2 + dataUpB.numLeavesInside,\n };\n }\n\n public traverseConjugate(conjugate: Conjugate, dataDown: DataDown): DataUp {\n const dataUpA = this.traverseAlg(conjugate.A, dataDown);\n const dataUpB = this.traverseAlg(conjugate.B, {\n numMovesSofar: dataDown.numMovesSofar + dataUpA.numLeavesInside,\n });\n return {\n tokens: dataUpA.tokens.concat(dataUpB.tokens),\n numLeavesInside:\n dataUpA.numLeavesInside * 2 + dataUpB.numLeavesInside * 2,\n };\n }\n\n public traversePause(pause: Pause, dataDown: DataDown): DataUp {\n return {\n tokens: [{ leaf: pause as Parsed<Pause>, idx: dataDown.numMovesSofar }],\n numLeavesInside: 1,\n }; // TODO: What if not parsed?\n }\n\n public traverseNewline(_newline: Newline, _dataDown: DataDown): DataUp {\n return {\n tokens: [],\n numLeavesInside: 0,\n };\n }\n\n public traverseLineComment(\n _comment: LineComment,\n _dataDown: DataDown,\n ): DataUp {\n return {\n tokens: [],\n numLeavesInside: 0,\n };\n }\n}\n\nconst leafTokensInstance = new LeafTokens();\nexport const leafTokens = leafTokensInstance.traverseAlg.bind(\n leafTokensInstance,\n) as (alg: Parsed<Alg>, dataDown: DataDown) => DataUp;\n", "// TODO: Move this?\n\nimport type { Alg } from \"../../../alg\";\nimport type { Parsed } from \"../../../alg/parse\";\nimport {\n AlgWithIssues,\n algWithIssuesFromString,\n} from \"../../model/props/puzzle/state/AlgProp\";\nimport {\n SimpleTwistyPropSource,\n TwistyPropDerived,\n TwistyPropSource,\n} from \"../../model/props/TwistyProp\";\nimport {\n AnimatedLeafUnitInfo,\n leafTokens,\n OrderedLeafTokens,\n} from \"./LeafTokens\";\n\nexport class TwistyAlgEditorValueProp extends SimpleTwistyPropSource<string> {\n getDefaultValue(): string {\n return \"\";\n }\n}\n\ninterface AlgEditorAlgWithIssuesPropInput {\n value: string;\n}\nclass AlgEditorAlgWithIssuesProp extends TwistyPropDerived<\n AlgEditorAlgWithIssuesPropInput,\n AlgWithIssues\n> {\n derive(input: AlgEditorAlgWithIssuesPropInput): AlgWithIssues {\n return algWithIssuesFromString(input.value);\n }\n\n // TODO: canReuse needs to take the source string into account.\n}\n\ninterface SelectionInfoPropInput {\n selectionStart: number;\n selectionEnd: number;\n}\ninterface SelectionInfo extends SelectionInfoPropInput {\n endChangedMostRecently: boolean;\n}\nexport class TwistyAlgEditorSelectionProp extends TwistyPropSource<\n SelectionInfo,\n SelectionInfoPropInput\n> {\n getDefaultValue() {\n return {\n selectionStart: 0,\n selectionEnd: 0,\n endChangedMostRecently: false,\n };\n }\n\n async derive(\n input: SelectionInfoPropInput,\n oldValue: Promise<SelectionInfo>,\n ): Promise<SelectionInfo> {\n const { selectionStart, selectionEnd } = input;\n const lastResult = await oldValue;\n const endChangedMostRecently =\n input.selectionStart === lastResult.selectionStart &&\n input.selectionEnd !== (await oldValue).selectionEnd;\n return {\n selectionStart,\n selectionEnd,\n endChangedMostRecently,\n };\n }\n}\n\ninterface TargetCharPropInputs {\n selectionInfo: SelectionInfo;\n}\n\nexport class TargetCharProp extends TwistyPropDerived<\n TargetCharPropInputs,\n number\n> {\n derive(inputs: TargetCharPropInputs) {\n return inputs.selectionInfo.endChangedMostRecently\n ? inputs.selectionInfo.selectionEnd\n : inputs.selectionInfo.selectionStart;\n }\n}\n\ninterface LeafTokensPropInputs {\n algWithIssues: AlgWithIssues;\n}\nclass LeafTokensProp extends TwistyPropDerived<\n LeafTokensPropInputs,\n OrderedLeafTokens\n> {\n derive(inputs: LeafTokensPropInputs): OrderedLeafTokens {\n return leafTokens(inputs.algWithIssues.alg as Parsed<Alg>, {\n numMovesSofar: 0,\n }).tokens;\n }\n}\n\ninterface LeafToHighlightPropInputs {\n targetChar: number;\n leafTokens: OrderedLeafTokens;\n}\ntype HighlightWhere = \"before\" | \"start\" | \"inside\" | \"end\" | \"after\";\nexport interface HighlightInfo {\n leafInfo: AnimatedLeafUnitInfo;\n where: HighlightWhere;\n}\nclass LeafToHighlightProp extends TwistyPropDerived<\n LeafToHighlightPropInputs,\n HighlightInfo | null\n> {\n derive(inputs: LeafToHighlightPropInputs): HighlightInfo | null {\n function withWhere(\n leafInfo: AnimatedLeafUnitInfo | null,\n ): HighlightInfo | null {\n if (leafInfo === null) {\n return null;\n }\n let where: HighlightWhere;\n if (inputs.targetChar < leafInfo.leaf.startCharIndex) {\n where = \"before\";\n } else if (inputs.targetChar === leafInfo.leaf.startCharIndex) {\n where = \"start\";\n } else if (inputs.targetChar < leafInfo.leaf.endCharIndex) {\n where = \"inside\";\n } else if (inputs.targetChar === leafInfo.leaf.endCharIndex) {\n where = \"end\";\n } else {\n where = \"after\";\n }\n return {\n leafInfo,\n where,\n };\n }\n\n let lastLeafInfo: AnimatedLeafUnitInfo | null = null;\n // TODO: binary search\n for (const leafInfo of inputs.leafTokens) {\n if (\n inputs.targetChar < leafInfo.leaf.startCharIndex &&\n lastLeafInfo !== null\n ) {\n return withWhere(lastLeafInfo);\n }\n if (inputs.targetChar <= leafInfo.leaf.endCharIndex) {\n return withWhere(leafInfo);\n }\n lastLeafInfo = leafInfo;\n }\n\n return withWhere(lastLeafInfo);\n }\n}\n\nexport class TwistyAlgEditorModel {\n valueProp = new TwistyAlgEditorValueProp();\n selectionProp = new TwistyAlgEditorSelectionProp();\n targetCharProp = new TargetCharProp({ selectionInfo: this.selectionProp });\n\n algEditorAlgWithIssues = new AlgEditorAlgWithIssuesProp({\n value: this.valueProp,\n });\n\n leafTokensProp = new LeafTokensProp({\n algWithIssues: this.algEditorAlgWithIssues,\n });\n\n leafToHighlight = new LeafToHighlightProp({\n leafTokens: this.leafTokensProp,\n targetChar: this.targetCharProp,\n });\n}\n", "import { CSSSource } from \"../ManagedCustomElement\";\n\nexport const twistyAlgEditorCSS = new CSSSource(`\n:host {\n width: 384px;\n display: grid;\n}\n\n.wrapper {\n /*overflow: hidden;\n resize: horizontal;*/\n\n background: var(--background, none);\n display: grid;\n}\n\ntextarea, .carbon-copy {\n grid-area: 1 / 1 / 2 / 2;\n\n width: 100%;\n font-family: sans-serif;\n line-height: 1.2em;\n\n font-size: var(--font-size, inherit);\n font-family: var(--font-family, sans-serif);\n\n box-sizing: border-box;\n\n padding: var(--padding, 0.5em);\n /* Prevent horizontal growth. */\n overflow-x: hidden;\n}\n\ntextarea {\n resize: none;\n background: none;\n z-index: 2;\n overflow: hidden;\n border: 1px solid var(--border-color, rgba(0, 0, 0, 0.25));\n}\n\n.carbon-copy {\n white-space: pre-wrap;\n word-wrap: break-word;\n color: transparent;\n user-select: none;\n pointer-events: none;\n\n z-index: 1;\n}\n\n.carbon-copy .highlight {\n background: var(--highlight-color, rgba(255, 128, 0, 0.5));\n padding: 0.1em 0.2em;\n margin: -0.1em -0.2em;\n border-radius: 0.2em;\n}\n\n.wrapper.issue-warning textarea,\n.wrapper.valid-for-puzzle-warning textarea {\n outline: none;\n border: 1px solid rgba(200, 200, 0, 0.5);\n background: rgba(255, 255, 0, 0.1);\n}\n\n.wrapper.issue-error textarea,\n.wrapper.valid-for-puzzle-error textarea {\n outline: none;\n border: 1px solid red;\n background: rgba(255, 0, 0, 0.1);\n}\n`);\n", "/**\n * Warning: the current implementation of <twisty-alg-editor> is *not good*,\n * but it is *good enough*. The important parts is that:\n *\n * - The editor can be used in apps without much effort.\n * - The editor handles alg validation and move highlighting *okay* when not\n * connected to a `<twisty-player>`.\n * - The editor stays in sync if it's connected to a `<twisty-player>`.\n *\n * The current implementation still has some race conditions and edge cases. A\n * proper rewrite with a better model would be very welcome.\n */\n\nimport type { ExperimentalParsed } from \"../../../alg\";\nimport { Alg, Move, Pause } from \"../../../alg\";\nimport type { Parsed } from \"../../../alg/parse\";\nimport type {\n AlgProp,\n AlgWithIssues,\n} from \"../../model/props/puzzle/state/AlgProp\";\nimport type { CurrentLeavesSimplified } from \"../../model/props/puzzle/state/CurrentLeavesSimplified\";\nimport { ClassListManager } from \"../ClassListManager\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { TwistyPlayer } from \"../TwistyPlayer\";\nimport { HighlightInfo, TwistyAlgEditorModel } from \"./model\";\nimport { twistyAlgEditorCSS } from \"./TwistyAlgEditor.css\";\n\nconst ATTRIBUTE_FOR_TWISTY_PLAYER = \"for-twisty-player\";\nconst ATTRIBUTE_PLACEHOLDER = \"placeholder\";\nconst ATTRIBUTE_TWISTY_PLAYER_PROP = \"twisty-player-prop\";\n\ntype TwistyPlayerAlgProp = \"alg\" | \"setupAlg\";\n\nexport class TwistyAlgEditor extends ManagedCustomElement {\n model = new TwistyAlgEditorModel();\n\n // #alg: Alg = new Alg();\n #textarea: HTMLTextAreaElement = document.createElement(\"textarea\");\n #carbonCopy: HTMLDivElement = document.createElement(\"div\");\n #carbonCopyPrefix: HTMLSpanElement = document.createElement(\"span\");\n #carbonCopyHighlight: HTMLSpanElement = document.createElement(\"span\");\n #carbonCopySuffix: HTMLSpanElement = document.createElement(\"span\");\n\n // #textareaClassListManager: ClassListManager<\"none\" | \"warning\" | \"error\"> =\n // new ClassListManager(this, \"issue-\", [\"none\", \"warning\", \"error\"]);\n\n #textareaClassListValidForPuzzleManager: ClassListManager<\n \"none\" | \"warning\" | \"error\"\n > = new ClassListManager(this, \"valid-for-puzzle-\", [\n \"none\",\n \"warning\",\n \"error\",\n ]);\n\n #twistyPlayer: TwistyPlayer | null = null;\n #twistyPlayerProp: TwistyPlayerAlgProp;\n get #algProp(): AlgProp | null {\n if (this.#twistyPlayer === null) {\n return null;\n } else {\n return this.#twistyPlayer.experimentalModel[this.#twistyPlayerProp];\n }\n }\n\n // Temporary Workaround for Twizzle Explorer\n debugNeverRequestTimestamp: boolean = false;\n\n constructor(options?: {\n twistyPlayer?: TwistyPlayer;\n twistyPlayerProp?: TwistyPlayerAlgProp;\n }) {\n super();\n this.#carbonCopy.classList.add(\"carbon-copy\");\n this.addElement(this.#carbonCopy);\n this.#textarea.rows = 1;\n this.addElement(this.#textarea);\n this.#carbonCopyPrefix.classList.add(\"prefix\");\n this.#carbonCopy.appendChild(this.#carbonCopyPrefix);\n this.#carbonCopyHighlight.classList.add(\"highlight\");\n this.#carbonCopy.appendChild(this.#carbonCopyHighlight);\n this.#carbonCopySuffix.classList.add(\"suffix\");\n this.#carbonCopy.appendChild(this.#carbonCopySuffix);\n\n this.#textarea.placeholder = \"Alg\";\n // Prevent iOS from defaulting to smart quotes.\n this.#textarea.setAttribute(\"spellcheck\", \"false\");\n\n this.addCSS(twistyAlgEditorCSS);\n\n // TODO: What set of events should we register? `change`? `keydown`?\n this.#textarea.addEventListener(\"input\", () => {\n this.#onInputHasFired = true;\n this.onInput();\n });\n this.#textarea.addEventListener(\"blur\", () => this.onBlur());\n document.addEventListener(\"selectionchange\", () =>\n this.onSelectionChange(),\n );\n\n if (options?.twistyPlayer) {\n this.twistyPlayer = options.twistyPlayer;\n }\n this.#twistyPlayerProp = options?.twistyPlayerProp ?? \"alg\";\n\n if (options?.twistyPlayerProp === \"alg\") {\n this.model.leafToHighlight.addFreshListener(\n (highlightInfo: HighlightInfo | null) => {\n if (highlightInfo) {\n this.highlightLeaf(highlightInfo.leafInfo.leaf);\n }\n },\n );\n }\n }\n\n // TODO\n set algString(s: string) {\n this.#textarea.value = s;\n this.onInput();\n }\n\n // TODO: remove?\n get algString(): string {\n return this.#textarea.value;\n }\n\n // To we need a getter?\n set placeholder(placeholderText: string) {\n this.#textarea.placeholder = placeholderText;\n }\n\n #onInputHasFired = false;\n onInput(): void {\n this.#carbonCopyHighlight.hidden = true;\n this.highlightLeaf(null);\n\n // TODO: This is a hack so that the you don't get a warning when the cursor\n // is after the space while typing `R U`. It would be nice to have something\n // cursor-aware that can also ignore whitespace warnings (or other syntax\n // errors due to normal input) adjacent to the cursor when it's in the\n // middle, but this is suffuciently useful for now.\n const endTrimmed = this.#textarea.value.trimEnd();\n this.model.valueProp.set(endTrimmed);\n this.#algProp?.set(endTrimmed);\n }\n\n async onSelectionChange(): Promise<void> {\n if (\n document.activeElement !== this ||\n this.shadow.activeElement !== this.#textarea\n ) {\n return;\n }\n if (this.#twistyPlayerProp !== \"alg\") {\n return;\n }\n\n const { selectionStart, selectionEnd } = this.#textarea;\n this.model.selectionProp.set({\n selectionStart,\n selectionEnd,\n });\n }\n\n async onBlur(): Promise<void> {\n // TODO: Figure out how not to make the cursor jump.\n // const parsed = Alg.fromString(this.algString);\n // this.algString = parsed.toString();\n // const [currentLeavesSimplified, indexer] = await Promise.all([\n // this.#twistyPlayer!.model.currentLeavesSimplifiedProp.get(),\n // this.#twistyPlayer!.model.indexerProp.get(),\n // ]);\n // const leaf = indexer.getAnimLeaf(currentLeavesSimplified.stateIndex);\n // this.highlightLeaf(leaf as Parsed<Move | Pause> | null);\n }\n\n setAlgIssueClassForPuzzle(issues: \"none\" | \"warning\" | \"error\") {\n this.#textareaClassListValidForPuzzleManager.setValue(issues);\n }\n\n // `white-space: pre;` mostly matches the formatting of the `<textarea>`, *except* when we end with a newline.\n // So we add an space to ensure that there is a character on the final line (that is very unlikely to trigger extra line wrapping).\n #padSuffix(s: string): string {\n return s.endsWith(\"\\n\") ? s + \" \" : s;\n }\n\n #highlightedLeaf: ExperimentalParsed<Move | Pause> | null = null;\n // TODO: support a primary highlighted move and secondary ones.\n highlightLeaf(leaf: ExperimentalParsed<Move | Pause> | null): void {\n if (this.#twistyPlayerProp !== \"alg\") {\n return;\n }\n if (leaf === null) {\n this.#carbonCopyPrefix.textContent = \"\";\n this.#carbonCopyHighlight.textContent = \"\";\n this.#carbonCopySuffix.textContent = this.#padSuffix(\n this.#textarea.value,\n );\n return;\n }\n if (leaf === this.#highlightedLeaf) {\n return;\n }\n this.#highlightedLeaf = leaf;\n this.#carbonCopyPrefix.textContent = this.#textarea.value.slice(\n 0,\n leaf.startCharIndex,\n );\n this.#carbonCopyHighlight.textContent = this.#textarea.value.slice(\n leaf.startCharIndex,\n leaf.endCharIndex,\n );\n this.#carbonCopySuffix.textContent = this.#padSuffix(\n this.#textarea.value.slice(leaf.endCharIndex),\n );\n this.#carbonCopyHighlight.hidden = false;\n }\n\n get twistyPlayer(): TwistyPlayer | null {\n return this.#twistyPlayer;\n }\n\n // TODO: spread out this impl over private methods instead of self-listeners.\n set twistyPlayer(twistyPlayer: TwistyPlayer | null) {\n if (this.#twistyPlayer) {\n // TODO: support reassigment/clearing\n console.warn(\"twisty-player reassignment/clearing is not supported\");\n return;\n }\n this.#twistyPlayer = twistyPlayer;\n if (!twistyPlayer) {\n return;\n }\n (async () => {\n this.algString = this.#algProp\n ? (await this.#algProp.get()).alg.toString()\n : \"\";\n })();\n\n if (this.#twistyPlayerProp === \"alg\") {\n // this.model.leafToHighlight.addFreshListener(\n // this.highlightLeaf.bind(this),\n // );\n\n // TODO: listen to puzzle prop?\n this.#twistyPlayer?.experimentalModel.puzzleAlg.addFreshListener(\n (algWithIssues: AlgWithIssues) => {\n // console.log(JSON.stringify(algWithIssues));\n if (algWithIssues.issues.errors.length === 0) {\n this.setAlgIssueClassForPuzzle(\n // TODO: Allow trailing spaces.\n algWithIssues.issues.warnings.length === 0 ? \"none\" : \"warning\",\n );\n const newAlg = algWithIssues.alg;\n const oldAlg = Alg.fromString(this.algString);\n if (!newAlg.isIdentical(oldAlg)) {\n this.algString = newAlg.toString();\n this.onInput();\n } else {\n // this.model.algInputProp.set(oldAlg);\n }\n } else {\n this.setAlgIssueClassForPuzzle(\"error\");\n }\n },\n );\n\n this.model.leafToHighlight.addFreshListener(\n async (highlightInfo: HighlightInfo | null) => {\n if (highlightInfo === null) {\n return;\n }\n // TODO: This indexer can be out of date!\n const [indexer, timestampRequest] = await Promise.all([\n await twistyPlayer.experimentalModel.indexer.get(),\n await twistyPlayer.experimentalModel.timestampRequest.get(),\n ]);\n if (\n timestampRequest === \"opposite-anchor\" &&\n !this.#onInputHasFired\n ) {\n return;\n }\n const moveStartTimestamp = indexer.indexToMoveStartTimestamp(\n highlightInfo.leafInfo.idx,\n );\n const duration = indexer.moveDuration(highlightInfo.leafInfo.idx);\n\n let newTimestamp: number;\n switch (highlightInfo.where) {\n case \"before\":\n newTimestamp = moveStartTimestamp;\n break;\n case \"start\":\n case \"inside\":\n newTimestamp = moveStartTimestamp + duration / 4;\n break;\n case \"end\":\n case \"after\":\n newTimestamp = moveStartTimestamp + duration;\n break;\n default:\n console.log(\"invalid where\");\n throw new Error(\"Invalid where!\");\n }\n if (!this.debugNeverRequestTimestamp) {\n twistyPlayer.experimentalModel.timestampRequest.set(newTimestamp);\n }\n },\n );\n\n twistyPlayer.experimentalModel.currentLeavesSimplified.addFreshListener(\n async (currentLeavesSimplified: CurrentLeavesSimplified) => {\n const indexer = await twistyPlayer.experimentalModel.indexer.get();\n const leaf = indexer.getAnimLeaf(currentLeavesSimplified.stateIndex);\n this.highlightLeaf(leaf as Parsed<Move | Pause> | null);\n },\n );\n }\n }\n\n protected attributeChangedCallback(\n attributeName: string,\n _oldValue: string,\n newValue: string,\n ): void {\n switch (attributeName) {\n case ATTRIBUTE_FOR_TWISTY_PLAYER: {\n const elem = document.getElementById(newValue);\n if (!elem) {\n console.warn(`${ATTRIBUTE_FOR_TWISTY_PLAYER}= elem does not exist`);\n return;\n }\n if (!(elem instanceof TwistyPlayer)) {\n // TODO: avoid assuming single instance of lib?\n console.warn(`${ATTRIBUTE_FOR_TWISTY_PLAYER}=is not a twisty-player`);\n return;\n }\n this.twistyPlayer = elem;\n return;\n }\n case ATTRIBUTE_PLACEHOLDER:\n this.placeholder = newValue;\n return;\n case ATTRIBUTE_TWISTY_PLAYER_PROP:\n if (this.#twistyPlayer) {\n console.log(\"cannot set prop\");\n throw new Error(\"cannot set prop after twisty player\");\n }\n this.#twistyPlayerProp = newValue as TwistyPlayerAlgProp;\n return;\n }\n }\n\n static get observedAttributes(): string[] {\n return [\n ATTRIBUTE_FOR_TWISTY_PLAYER,\n ATTRIBUTE_PLACEHOLDER,\n ATTRIBUTE_TWISTY_PLAYER_PROP,\n ];\n }\n}\n\ncustomElementsShim.define(\"twisty-alg-editor\", TwistyAlgEditor);\ndeclare global {\n interface HTMLElementTagNameMap {\n \"twisty-alg-editor\": TwistyAlgEditor;\n }\n}\n", "import { CSSSource } from \"../ManagedCustomElement\";\n\nexport const twizzleLinkCSS = new CSSSource(`\n.wrapper {\n background: rgb(255, 245, 235);\n display: grid;\n grid-template-columns: 1fr;\n border: 1px solid rgba(0, 0, 0, 0.25);\n}\n\n.setup-alg, twisty-alg-viewer {\n padding: 0.5em 1em;\n}\n\n.heading {\n background: rgba(255, 230, 210, 1);\n font-weight: bold;\n padding: 0.25em 0.5em;\n}\n\n.heading.title {\n background: rgb(255, 245, 235);\n font-size: 150%;\n white-space: pre;\n}\n\ntwisty-player {\n width: 100%;\n resize: vertical;\n overflow-y: hidden;\n}\n\ntwisty-player + .heading {\n padding-top: 0.5em;\n}\n`);\n", "import { EXPERIMENTAL_PROP_NO_VALUE } from \"../../../../cubing/twisty\";\nimport type {\n AlgProp,\n AlgWithIssues,\n} from \"../../../../cubing/twisty/model/props/puzzle/state/AlgProp\";\nimport type { TwistyPlayerModel } from \"../../../../cubing/twisty/model/TwistyPlayerModel\";\nimport type { TwistyPropSource } from \"../../../../cubing/twisty/model/props/TwistyProp\";\nimport {\n TwistyPlayerAttribute,\n twistyPlayerAttributeMap,\n TwistyPlayerConfig,\n} from \"../../../../cubing/twisty/views/TwistyPlayer\";\n\nfunction updateURL(url: URL): void {\n window.history.replaceState(\"\", \"\", url.toString());\n}\n\n// TODO: Find a way to connect this to the `TwistyPlayer` constructor?\n\nexport type URLParamUpdaterOptions = {\n prefix?: string;\n};\n\nexport class URLParamUpdater {\n #prefix: string;\n constructor(model: TwistyPlayerModel, options?: URLParamUpdaterOptions) {\n this.#prefix = options?.prefix ?? \"\";\n\n this.listenToAlgProp(model.alg, \"alg\");\n this.listenToAlgProp(model.setupAlg, \"setup-alg\");\n this.listenToStringSourceProp(\n model.twistySceneModel.stickering,\n \"stickering\",\n );\n this.listenToStringSourceProp(model.setupAnchor, \"setup-anchor\");\n this.listenToStringOrNullProp(model.title, \"title\");\n this.listenToStringOrNoValueProp(\n model.puzzleIDRequest,\n \"puzzle\",\n EXPERIMENTAL_PROP_NO_VALUE,\n );\n this.listenToStringOrNoValueProp(\n model.puzzleDescriptionRequest,\n \"puzzle-description\",\n EXPERIMENTAL_PROP_NO_VALUE,\n );\n }\n\n // TODO: Cache parsed URL?\n setURLParam(\n unprefixedKey: string,\n value: string,\n defaultString: string,\n ): void {\n const prefixedKey = this.#prefix + unprefixedKey;\n const url = new URL(location.href);\n if (value === defaultString) {\n url.searchParams.delete(prefixedKey);\n } else {\n url.searchParams.set(prefixedKey, value);\n }\n updateURL(url);\n }\n\n async listenToStringSourceProp(\n prop: TwistyPropSource<string>,\n key: string,\n defaultString?: string,\n ): Promise<void> {\n const actualDefaultString = defaultString ?? (await prop.getDefaultValue());\n prop.addFreshListener((s: string) => {\n this.setURLParam(key, s, actualDefaultString);\n });\n }\n\n async listenToStringOrNullProp(\n prop: TwistyPropSource<string | null>,\n key: string,\n defaultString: string = \"\",\n ): Promise<void> {\n prop.addFreshListener((s: string | null) => {\n this.setURLParam(key, s ?? defaultString, defaultString);\n });\n }\n\n async listenToStringOrNoValueProp(\n prop: TwistyPropSource<string | typeof EXPERIMENTAL_PROP_NO_VALUE>,\n key: string,\n defaultString: string | typeof EXPERIMENTAL_PROP_NO_VALUE,\n ): Promise<void> {\n prop.addFreshListener((s: string | typeof EXPERIMENTAL_PROP_NO_VALUE) => {\n if (s === EXPERIMENTAL_PROP_NO_VALUE) {\n s = defaultString;\n }\n if (s === EXPERIMENTAL_PROP_NO_VALUE) {\n this.setURLParam(key, \"\", \"\");\n } else {\n this.setURLParam(key, s, \"\"); // TODO\n }\n });\n }\n\n listenToAlgProp(prop: AlgProp, key: string): void {\n prop.addFreshListener((algWithIssues: AlgWithIssues) => {\n this.setURLParam(key, algWithIssues.alg.toString(), \"\");\n });\n }\n}\n\nexport function getConfigFromURL(\n prefix = \"\",\n url: string = location.href,\n): TwistyPlayerConfig {\n // TODO: Why does `Object.entries(paramMapping)` crash if this is defined elswhere?\n const paramMapping: Record<string, TwistyPlayerAttribute> = {\n \"alg\": \"alg\",\n \"setup-alg\": \"experimental-setup-alg\",\n \"setup-anchor\": \"experimental-setup-anchor\",\n \"puzzle\": \"puzzle\",\n \"stickering\": \"experimental-stickering\",\n \"puzzle-description\": \"experimental-puzzle-description\",\n \"title\": \"experimental-title\",\n \"video-url\": \"experimental-video-url\",\n \"competition\": \"experimental-competition-id\",\n };\n\n const params = new URL(url).searchParams;\n const config: TwistyPlayerConfig = {};\n for (const [ourParam, twistyPlayerParam] of Object.entries(paramMapping)) {\n const paramValue = params.get(prefix + ourParam);\n if (paramValue !== null) {\n // TODO: type\n const configKey = twistyPlayerAttributeMap[twistyPlayerParam];\n (config as any)[configKey] = paramValue;\n }\n }\n return config;\n}\n\nexport function remapLegacyURLParams(\n mapping: Record<string, string | null>,\n): void {\n const url = new URL(location.href);\n for (const [oldKey, newKey] of Object.entries(mapping)) {\n // `null` indicates there is no new key, i.e. just drop the old key\n if (newKey !== null) {\n // The new key takes precedents, so we only remap the old key if the new key\n // is not already set.\n if (!url.searchParams.has(newKey)) {\n const value = url.searchParams.get(oldKey);\n if (value !== null) {\n url.searchParams.set(newKey, value);\n }\n }\n }\n url.searchParams.delete(oldKey);\n }\n updateURL(url);\n}\n", "import { TwistyPlayer } from \"../..\";\nimport { Alg } from \"../../../alg\";\nimport { puzzles } from \"../../../puzzles\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { TwistyAlgViewer } from \"../TwistyAlgViewer\";\nimport { twizzleLinkCSS } from \"./TwizzleLink.css\";\nimport { getConfigFromURL } from \"./url-params\";\n\nexport class TwizzleLink extends ManagedCustomElement {\n twistyPlayer: TwistyPlayer | null = null;\n a: HTMLAnchorElement | null = null;\n constructor() {\n super({ mode: \"open\" });\n }\n\n fallback() {\n this.contentWrapper.textContent = \"\";\n if (this.a) {\n const span = this.contentWrapper.appendChild(\n document.createElement(\"span\"),\n );\n span.textContent = \"\u2757\uFE0F\";\n span.title = \"Could not show a player for link\";\n this.addElement(this.a);\n }\n if (this.#cssElem) {\n this.#cssElem.remove();\n }\n }\n\n #cssElem: HTMLStyleElement | undefined;\n async connectedCallback() {\n this.#cssElem = this.addCSS(twizzleLinkCSS);\n this.a = this.querySelector(\"a\");\n if (!this.a) {\n return;\n }\n\n const config = getConfigFromURL(\"\", this.a.href);\n\n const href = this.a?.href;\n const { hostname, pathname } = new URL(href);\n\n if (hostname !== \"alpha.twizzle.net\") {\n this.fallback();\n return;\n }\n if ([\"/edit/\", \"/explore/\"].includes(pathname)) {\n const isExplorer = pathname === \"/explore/\";\n\n if (config.puzzle && !(config.puzzle in puzzles)) {\n const puzzleDescription = (\n await import(\"../../../puzzle-geometry\")\n ).getPuzzleDescriptionString(config.puzzle);\n delete config.puzzle;\n config.experimentalPuzzleDescription = puzzleDescription;\n }\n\n this.twistyPlayer = this.addElement(\n new TwistyPlayer({\n ...config,\n viewerLink: isExplorer ? \"experimental-twizzle-explorer\" : \"auto\",\n }),\n );\n\n if (config.experimentalTitle) {\n this.addHeading(config.experimentalTitle).classList.add(\"title\");\n // const setupAlgDiv = this.addElement(document.createElement(\"div\"));\n // setupAlgDiv.classList.add(\"setup-alg\");\n // setupAlgDiv.textContent = puzzles[config.puzzle ?? \"3x3x3\"].fullName;\n }\n\n if (config.experimentalSetupAlg) {\n this.addHeading(\"Setup\");\n\n const setupAlgDiv = this.addElement(document.createElement(\"div\"));\n setupAlgDiv.classList.add(\"setup-alg\");\n setupAlgDiv.textContent = new Alg(\n config.experimentalSetupAlg,\n ).toString();\n }\n this.addHeading(\"Moves\");\n const twistyAlgViewer = this.addElement(\n new TwistyAlgViewer({ twistyPlayer: this.twistyPlayer }),\n );\n twistyAlgViewer.part.add(\"twisty-alg-viewer\");\n } else {\n this.fallback();\n }\n }\n\n addHeading(text: string): HTMLElement {\n const headingDiv = this.addElement(document.createElement(\"div\"));\n headingDiv.classList.add(\"heading\");\n headingDiv.textContent = text;\n return headingDiv;\n }\n}\n\ncustomElementsShim.define(\"twizzle-link\", TwizzleLink);\ndeclare global {\n interface HTMLElementTagNameMap {\n \"twizzle-link\": TwizzleLink;\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type { Move } from \"../../alg\";\nimport type { KState } from \"../../kpuzzle/KState\";\n\nexport type MillisecondTimestamp = number;\n\n// TODO: unify duration/timstamp types\nexport type Duration = MillisecondTimestamp; // Duration in milliseconds\n// TODO: Extend `number`, introduce MoveSequenceTimestamp vs. EpochTimestamp,\n// force Duration to be a difference.\nexport type Timestamp = MillisecondTimestamp; // Duration since a particular epoch.\n\nexport type Fraction = number; // Value from 0 to 1.\n\n// 1, 0, -1 are used as scalars for `directionScalar` below.\nexport enum Direction {\n Forwards = 1,\n Paused = 0,\n Backwards = -1,\n}\n\nexport function directionScalar(direction: Direction): MillisecondTimestamp {\n return direction;\n}\n\nexport interface MoveInProgress {\n move: Move;\n direction: Direction;\n fraction: number;\n}\n\nexport type PuzzlePosition = {\n state: KState;\n movesInProgress: MoveInProgress[];\n};\n\nexport enum BoundaryType {\n Move = \"move\",\n EntireTimeline = \"entire-timeline\",\n}\n\nexport interface TimeRange {\n start: MillisecondTimestamp;\n end: MillisecondTimestamp;\n}\n\n// export type DurationForAmount = (amount: number) => Duration;\n\nexport interface PositionListener {\n onPositionChange(position: PuzzlePosition): void;\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: DOMHighResTimeStamp) => void) {}\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);\n }\n}\n\n// An interface for classes to use to expose their scheduling.\nexport interface Schedulable {\n scheduleRender(): void;\n}\n", "export function arrayEquals<T>(a: readonly T[], b: readonly T[]): boolean {\n if (a === b) {\n return true;\n }\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n}\n\nexport function arrayEqualsCompare<T>(\n a: readonly T[],\n b: readonly T[],\n compare: (a: T, b: T) => boolean,\n): boolean {\n if (a === b) {\n return true;\n }\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (!compare(a[i], b[i])) {\n return false;\n }\n }\n return true;\n}\n\n// Assumes `offset > 0`. Will produce invalid values if not!\n// We don't check for that, since this can be a hot path.\nexport function mod(v: number, m: number, offset = 0): number {\n return (((v % m) + m + offset) % m) - offset;\n}\n\nexport function modIntoRange(\n v: number,\n rangeMin: number,\n rangeMax: number,\n): number {\n return mod(v - rangeMin, rangeMax - rangeMin) + rangeMin;\n}\n", "import {\n BoundaryType,\n Direction,\n directionScalar,\n MillisecondTimestamp,\n TimeRange,\n} from \"./AnimationTypes\";\nimport { RenderScheduler } from \"./RenderScheduler\";\nimport type {\n PlayingInfo,\n SimpleDirection,\n} from \"../model/props/timeline/PlayingInfoProp\";\nimport type { TwistyPlayerModel } from \"../model/TwistyPlayerModel\";\nimport { StaleDropper } from \"../model/PromiseFreshener\";\nimport type { CurrentMoveInfo } from \"./indexer/AlgIndexer\";\nimport type { TimestampRequest } from \"../model/props/timeline/TimestampRequestProp\";\nimport { modIntoRange } from \"../model/helpers\";\nimport type { CatchUpMove } from \"../model/props/puzzle/state/CatchUpMoveProp\";\n\n// TODO: Figure out a better way for the controller to instruct the player.\nexport interface TwistyAnimationControllerDelegate {\n flash(): void;\n}\n\n// We use a separate helper to separate the anim frame callbacks (and their cancellations).\n// TODO: fold this into the main controller\nclass CatchUpHelper {\n catchingUp: boolean = false;\n pendingFrame = false;\n\n constructor(private model: TwistyPlayerModel) {}\n\n private scheduler: RenderScheduler = new RenderScheduler(\n this.animFrame.bind(this),\n );\n\n start(): void {\n if (!this.catchingUp) {\n this.lastTimestamp = performance.now();\n }\n this.catchingUp = true;\n this.pendingFrame = true;\n this.scheduler.requestAnimFrame();\n }\n\n stop(): void {\n this.catchingUp = false;\n this.scheduler.cancelAnimFrame();\n }\n\n catchUpMs = 500;\n lastTimestamp = 0;\n animFrame(timestamp: MillisecondTimestamp): void {\n this.scheduler.requestAnimFrame();\n const delta = (timestamp - this.lastTimestamp) / this.catchUpMs;\n this.lastTimestamp = timestamp;\n\n this.model.catchUpMove.set(\n (async () => {\n const previousCatchUpMove = await this.model.catchUpMove.get();\n if (previousCatchUpMove.move === null) {\n return previousCatchUpMove;\n }\n\n const amount = previousCatchUpMove.amount + delta; // TODO: use tempo scale?\n if (amount >= 1) {\n this.pendingFrame = true;\n this.stop();\n this.model.timestampRequest.set(\"end\");\n return {\n move: null,\n amount: 0,\n };\n }\n this.pendingFrame = false;\n return {\n move: previousCatchUpMove.move,\n amount: amount,\n };\n })(),\n );\n }\n}\n\n// This controls the logic for animation, so that the main controller can focus on the right API abstractions.\nexport class TwistyAnimationController {\n // TODO: #private?\n private playing: boolean = false;\n private direction: Direction = Direction.Forwards;\n\n private catchUpHelper: CatchUpHelper;\n\n private model: TwistyPlayerModel;\n\n private lastDatestamp: MillisecondTimestamp = 0;\n private lastTimestampPromise: Promise<MillisecondTimestamp>;\n\n private scheduler: RenderScheduler = new RenderScheduler(\n this.animFrame.bind(this),\n );\n\n constructor(\n model: TwistyPlayerModel,\n private delegate: TwistyAnimationControllerDelegate,\n ) {\n this.model = model;\n this.lastTimestampPromise = this.#effectiveTimestampMilliseconds();\n\n this.model.playingInfo.addFreshListener(this.onPlayingProp.bind(this)); // TODO\n\n this.catchUpHelper = new CatchUpHelper(this.model);\n this.model.catchUpMove.addFreshListener(this.onCatchUpMoveProp.bind(this)); // TODO\n }\n\n // TODO: Do we need this?\n async onPlayingProp(playingInfo: PlayingInfo): Promise<void> {\n if (playingInfo.playing !== this.playing) {\n playingInfo.playing ? this.play(playingInfo) : this.pause();\n }\n }\n\n // TODO: Do we need this?\n async onCatchUpMoveProp(catchUpMove: CatchUpMove): Promise<void> {\n const catchingUp = catchUpMove.move !== null;\n if (catchingUp !== this.catchUpHelper.catchingUp) {\n catchingUp ? this.catchUpHelper.start() : this.catchUpHelper.stop();\n }\n this.scheduler.requestAnimFrame();\n }\n\n async #effectiveTimestampMilliseconds(): Promise<MillisecondTimestamp> {\n return (await this.model.detailedTimelineInfo.get()).timestamp;\n }\n\n // TODO: Return the animation we've switched to.\n jumpToStart(options?: { flash: boolean }): void {\n this.model.timestampRequest.set(\"start\");\n this.pause();\n if (options?.flash) {\n this.delegate.flash();\n }\n }\n\n // TODO: Return the animation we've switched to.\n jumpToEnd(options?: { flash: boolean }): void {\n this.model.timestampRequest.set(\"end\");\n this.pause();\n if (options?.flash) {\n this.delegate.flash();\n }\n }\n\n // TODO: Return the playing info we've switched to.\n playPause(): void {\n if (this.playing) {\n this.pause();\n } else {\n this.play(); // TODO: Resume direction and looping behaviour?\n }\n }\n\n // TODO: bundle playing direction, and boundary into `toggle`.\n async play(options?: {\n direction?: SimpleDirection;\n untilBoundary?: BoundaryType;\n autoSkipToOtherEndIfStartingAtBoundary?: boolean; // TODO What's a good short name that doesn't imply a more general looping concept?\n loop?: boolean;\n }): Promise<void> {\n // TODO: We might need to cache all playing info?\n // Or maybe we don't have to worry about short-circuiting, since this is idempotent?\n // if (this.playing) {\n // return;\n // }\n\n const direction = options?.direction ?? Direction.Forwards;\n\n const coarseTimelineInfo = await this.model.coarseTimelineInfo.get(); // TODO: Why do we need to read this if we don't use it?\n if (options?.autoSkipToOtherEndIfStartingAtBoundary ?? true) {\n if (direction === Direction.Forwards && coarseTimelineInfo.atEnd) {\n this.model.timestampRequest.set(\"start\");\n this.delegate.flash();\n }\n if (direction === Direction.Backwards && coarseTimelineInfo.atStart) {\n this.model.timestampRequest.set(\"end\");\n this.delegate.flash();\n }\n }\n this.model.playingInfo.set({\n playing: true,\n direction,\n untilBoundary: options?.untilBoundary ?? BoundaryType.EntireTimeline,\n loop: options?.loop ?? false,\n });\n\n this.playing = true;\n this.lastDatestamp = performance.now(); // TODO: Take from event.\n this.lastTimestampPromise = this.#effectiveTimestampMilliseconds();\n\n // TODO: Save timestamp from model?\n this.scheduler.requestAnimFrame();\n }\n\n pause(): void {\n this.playing = false;\n this.scheduler.cancelAnimFrame();\n this.model.playingInfo.set({\n playing: false,\n untilBoundary: BoundaryType.EntireTimeline,\n });\n }\n\n #animFrameEffectiveTimestampStaleDropper: StaleDropper<\n [PlayingInfo, MillisecondTimestamp, TimeRange, number, CurrentMoveInfo]\n > = new StaleDropper<\n [PlayingInfo, MillisecondTimestamp, TimeRange, number, CurrentMoveInfo]\n >();\n\n async animFrame(frameDatestamp: MillisecondTimestamp): Promise<void> {\n if (this.playing) {\n this.scheduler.requestAnimFrame();\n }\n\n const lastDatestamp = this.lastDatestamp;\n const freshenerResult =\n await this.#animFrameEffectiveTimestampStaleDropper.queue(\n Promise.all([\n this.model.playingInfo.get(),\n this.lastTimestampPromise,\n this.model.timeRange.get(),\n this.model.tempoScale.get(),\n this.model.currentMoveInfo.get(),\n ]),\n );\n\n const [playingInfo, lastTimestamp, timeRange, tempoScale, currentMoveInfo] =\n freshenerResult;\n\n // TODO: Get this without wasting time on the others?\n if (!playingInfo.playing) {\n this.playing = false;\n // TODO: Ideally we'd cancel the anim frame from the top of this method.\n // But `this.scheduler.cancelAnimFrame();` might accidentally cancel a\n // legit freshly scheduled frame. We should modify `RenderScheduler` to\n // either have individually cancellable requests, or to have something\n // like a \"default\" anim frame re-request that can be canceled separately.\n //\n // Note that we can't wait until here to call\n // `this.scheduler.requestAnimFrame();`, because that would slow down the\n // frame rate.\n return;\n }\n\n let end = currentMoveInfo.earliestEnd; // timeRange.end\n if (\n currentMoveInfo.currentMoves.length === 0 ||\n playingInfo.untilBoundary === BoundaryType.EntireTimeline\n ) {\n end = timeRange.end;\n }\n\n let start = currentMoveInfo.latestStart; // timeRange.end\n if (\n currentMoveInfo.currentMoves.length === 0 ||\n playingInfo.untilBoundary === BoundaryType.EntireTimeline\n ) {\n start = timeRange.start;\n }\n // const start = currentMoveInfo.latestStart; // timeRange.start // TODO\n\n let delta =\n (frameDatestamp - lastDatestamp) *\n directionScalar(this.direction) *\n tempoScale;\n delta = Math.max(delta, 1); // TODO: This guards against the timestamp going in the wrong direction by accident. Can we avoid it?\n delta *= playingInfo.direction;\n let newTimestamp = lastTimestamp + delta; // TODO: Pre-emptively clamp.\n let newSmartTimestampRequest: Exclude<TimestampRequest, number> | null =\n null;\n\n if (newTimestamp >= end) {\n if (playingInfo.loop) {\n newTimestamp = modIntoRange(\n newTimestamp,\n timeRange.start,\n timeRange.end,\n );\n } else {\n if (newTimestamp === timeRange.end) {\n newSmartTimestampRequest = \"end\";\n } else {\n newTimestamp = end;\n }\n this.playing = false;\n this.model.playingInfo.set({\n playing: false,\n });\n }\n } else if (newTimestamp <= start) {\n if (playingInfo.loop) {\n newTimestamp = modIntoRange(\n newTimestamp,\n timeRange.start,\n timeRange.end,\n );\n } else {\n if (newTimestamp === timeRange.start) {\n newSmartTimestampRequest = \"start\";\n } else {\n newTimestamp = start;\n }\n this.playing = false;\n this.model.playingInfo.set({\n playing: false,\n });\n }\n }\n this.lastDatestamp = frameDatestamp;\n this.lastTimestampPromise = Promise.resolve(newTimestamp); // TODO: Save this earlier? / Do we need to worry about the effecitve timestamp disagreeing?\n this.model.timestampRequest.set(newSmartTimestampRequest ?? newTimestamp);\n }\n}\n", "import type { TwistyPlayerModel } from \"../model/TwistyPlayerModel\";\nimport {\n TwistyAnimationController,\n TwistyAnimationControllerDelegate,\n} from \"./TwistyAnimationController\";\n\nexport class TwistyPlayerController {\n animationController: TwistyAnimationController;\n\n constructor(\n private model: TwistyPlayerModel,\n delegate: TwistyAnimationControllerDelegate,\n ) {\n this.animationController = new TwistyAnimationController(model, delegate);\n }\n\n jumpToStart(options?: { flash: boolean }): void {\n this.animationController.jumpToStart(options);\n }\n\n jumpToEnd(options?: { flash: boolean }): void {\n this.animationController.jumpToEnd(options);\n }\n\n togglePlay(play?: boolean) {\n if (typeof play === \"undefined\") {\n this.animationController.playPause();\n }\n play ? this.animationController.play() : this.animationController.pause();\n }\n\n public async visitTwizzleLink(): Promise<void> {\n const a = document.createElement(\"a\");\n a.href = await this.model.twizzleLink();\n a.target = \"_blank\";\n a.click();\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nexport const controlsLocations = {\n \"bottom-row\": true, // default\n \"none\": true,\n};\nexport type ControlsLocation = keyof typeof controlsLocations;\nexport type ControlPanelThemeWithAuto = ControlsLocation | \"auto\";\n\nexport class ControlPanelProp extends SimpleTwistyPropSource<ControlPanelThemeWithAuto> {\n getDefaultValue(): ControlPanelThemeWithAuto {\n return \"auto\";\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 = 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 = customElements;\n} else {\n customElementsShim = new CustomElementsStub() as any;\n}\n\nexport { customElementsShim };\n", "import {\n HTMLElementShim,\n customElementsShim,\n} from \"./node-custom-element-shims\";\n\nexport class CSSSource {\n constructor(private sourceText: string) {\n // TODO: Replace with adopted style sheets some day if we can.\n // const blob = new Blob([sourceText], {\n // type: \"text/utf8\",\n // });\n // this.url = URL.createObjectURL(blob);\n }\n\n getAsString(): string {\n return this.sourceText;\n }\n}\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 #cssSourceMap: Map<CSSSource, HTMLStyleElement> = new Map();\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 public addCSS(cssSource: CSSSource): HTMLStyleElement {\n const existing = this.#cssSourceMap.get(cssSource);\n if (existing) {\n return existing;\n }\n\n const cssElem: HTMLStyleElement = document.createElement(\"style\");\n cssElem.textContent = cssSource.getAsString();\n\n this.#cssSourceMap.set(cssSource, cssElem);\n this.shadow.appendChild(cssElem);\n return cssElem;\n }\n\n // Remove the source, if it's currently added.\n public removeCSS(cssSource: CSSSource): void {\n const cssElem = this.#cssSourceMap.get(cssSource);\n if (!cssElem) {\n return;\n }\n this.shadow.removeChild(cssElem);\n this.#cssSourceMap.delete(cssSource);\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 { CSSSource } from \"./ManagedCustomElement\";\n\nexport const twistyViewerWrapperCSS = new CSSSource(`\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}\n\n.wrapper > * {\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n.wrapper.back-view-side-by-side {\n grid-template-columns: 1fr 1fr;\n}\n\n.wrapper.back-view-top-right {\n grid-template-columns: 3fr 1fr;\n grid-template-rows: 1fr 3fr;\n}\n\n.wrapper.back-view-top-right > :nth-child(1) {\n grid-row: 1 / 3;\n grid-column: 1 / 3;\n}\n\n.wrapper.back-view-top-right > :nth-child(2) {\n grid-row: 1 / 2;\n grid-column: 2 / 3;\n}\n`);\n", "import { CSSSource } from \"../ManagedCustomElement\";\n\n// TODO: Can we do this without so much nesting, and styling all the nested elems?\nexport const twisty2DSVGCSS = new CSSSource(`\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}\n\n.svg-wrapper,\ntwisty-2d-svg,\nsvg {\n width: 100%;\n height: 100%;\n display: grid;\n min-height: 0;\n}\n\nsvg {\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", "import type { KPuzzle } from \"../../../kpuzzle\";\nimport type { KState } from \"../../../kpuzzle/KState\";\nimport type {\n FaceletMeshAppearance,\n PuzzleAppearance,\n} from \"../../../puzzles/stickerings/appearance\"; // TODO\nconst xmlns = \"http://www.w3.org/2000/svg\";\n\n// Unique ID mechanism to keep SVG gradient element IDs unique. TODO: Is there\n// something more performant, and that can't be broken by other elements of the\n// page? (And also doesn't break if this library is run in parallel.)\nlet svgCounter = 0;\nfunction nextSVGID(): string {\n svgCounter += 1;\n return \"svg\" + svgCounter.toString();\n}\n\n// TODO: This is hardcoded to 3x3x3 SVGs\nconst colorMaps: Partial<\n Record<FaceletMeshAppearance, Record<string, string>>\n> = {\n dim: {\n \"white\": \"#dddddd\",\n \"orange\": \"#884400\",\n \"limegreen\": \"#008800\",\n \"red\": \"#660000\",\n \"rgb(34, 102, 255)\": \"#000088\", // TODO\n \"yellow\": \"#888800\",\n },\n oriented: {\n \"white\": \"#44ddcc\",\n \"orange\": \"#44ddcc\",\n \"limegreen\": \"#44ddcc\",\n \"red\": \"#44ddcc\",\n \"rgb(34, 102, 255)\": \"#44ddcc\", // TODO\n \"yellow\": \"#44ddcc\",\n },\n ignored: {\n \"white\": \"#444444\",\n \"orange\": \"#444444\",\n \"limegreen\": \"#444444\",\n \"red\": \"#444444\",\n \"rgb(34, 102, 255)\": \"#444444\", // TODO\n \"yellow\": \"#444444\",\n },\n invisible: {\n \"white\": \"#00000000\",\n \"orange\": \"#00000000\",\n \"limegreen\": \"#00000000\",\n \"red\": \"#00000000\",\n \"rgb(34, 102, 255)\": \"#00000000\", // TODO\n \"yellow\": \"#00000000\",\n },\n};\n\nexport class KPuzzleSVGWrapper {\n public element: HTMLElement;\n public gradientDefs: SVGDefsElement;\n private originalColors: { [type: string]: string } = {};\n private gradients: { [type: string]: SVGGradientElement } = {};\n private svgID: string;\n constructor(\n public kpuzzle: KPuzzle,\n svgSource: string,\n experimentalAppearance?: PuzzleAppearance,\n ) {\n if (!svgSource) {\n throw new Error(`No SVG definition for puzzle type: ${kpuzzle.name()}`);\n }\n\n this.svgID = nextSVGID();\n\n this.element = document.createElement(\"div\");\n this.element.classList.add(\"svg-wrapper\");\n // TODO: Sanitization.\n this.element.innerHTML = svgSource;\n\n const svgElem = this.element.querySelector(\"svg\");\n if (!svgElem) {\n throw new Error(\"Could not get SVG element\");\n }\n if (xmlns !== svgElem.namespaceURI) {\n throw new Error(\"Unexpected XML namespace\");\n }\n svgElem.style.maxWidth = \"100%\";\n svgElem.style.maxHeight = \"100%\";\n this.gradientDefs = document.createElementNS(xmlns, \"defs\");\n svgElem.insertBefore(this.gradientDefs, svgElem.firstChild);\n\n for (const orbitName in kpuzzle.definition.orbits) {\n const orbitDefinition = kpuzzle.definition.orbits[orbitName];\n\n for (let idx = 0; idx < orbitDefinition.numPieces; idx++) {\n for (\n let orientation = 0;\n orientation < orbitDefinition.numOrientations;\n orientation++\n ) {\n const id = this.elementID(orbitName, idx, orientation);\n const elem = this.elementByID(id);\n let originalColor: string = elem.style.fill;\n /// TODO: Allow setting appearance dynamically.\n if (experimentalAppearance) {\n (() => {\n // TODO: dedup with Cube3D,,factor out fallback calculations\n const a = experimentalAppearance.orbits;\n if (!a) {\n return;\n }\n const orbitAppearance = a[orbitName];\n if (!orbitAppearance) {\n return;\n }\n const pieceAppearance = orbitAppearance.pieces[idx];\n if (!pieceAppearance) {\n return;\n }\n const faceletAppearance = pieceAppearance.facelets[orientation];\n if (!faceletAppearance) {\n return;\n }\n const appearance =\n typeof faceletAppearance === \"string\"\n ? faceletAppearance\n : faceletAppearance?.appearance;\n const colorMap = colorMaps[appearance];\n if (colorMap) {\n originalColor = colorMap[originalColor];\n }\n })();\n } else {\n originalColor = elem.style.fill;\n }\n this.originalColors[id] = originalColor;\n this.gradients[id] = this.newGradient(id, originalColor);\n this.gradientDefs.appendChild(this.gradients[id]);\n elem.setAttribute(\"style\", `fill: url(#grad-${this.svgID}-${id})`);\n }\n }\n }\n }\n\n public drawState(state: KState, nextState?: KState, fraction?: number): void {\n this.draw(state, nextState, fraction);\n }\n\n // TODO: save definition in the constructor?\n public draw(state: KState, nextState?: KState, fraction?: number): void {\n const transformation = state.experimentalToTransformation();\n const nextTransformation = nextState?.experimentalToTransformation();\n if (!transformation) {\n throw new Error(\"Distinguishable pieces are not handled for SVG yet!\");\n }\n\n for (const orbitName in transformation.kpuzzle.definition.orbits) {\n const orbitDefinition =\n transformation.kpuzzle.definition.orbits[orbitName];\n\n const curTransformationOrbit =\n transformation.transformationData[orbitName];\n const nextTransformationOrbit = nextTransformation\n ? nextTransformation.transformationData[orbitName]\n : null;\n for (let idx = 0; idx < orbitDefinition.numPieces; idx++) {\n for (\n let orientation = 0;\n orientation < orbitDefinition.numOrientations;\n orientation++\n ) {\n const id = this.elementID(orbitName, idx, orientation);\n const fromCur = this.elementID(\n orbitName,\n curTransformationOrbit.permutation[idx],\n (orbitDefinition.numOrientations -\n curTransformationOrbit.orientation[idx] +\n orientation) %\n orbitDefinition.numOrientations,\n );\n let singleColor = false;\n if (nextTransformationOrbit) {\n const fromNext = this.elementID(\n orbitName,\n nextTransformationOrbit.permutation[idx],\n (orbitDefinition.numOrientations -\n nextTransformationOrbit.orientation[idx] +\n orientation) %\n orbitDefinition.numOrientations,\n );\n if (fromCur === fromNext) {\n singleColor = true; // TODO: Avoid redundant work during move.\n }\n fraction = fraction || 0; // TODO Use the type system to tie this to nextState?\n const easedBackwardsPercent =\n 100 * (1 - fraction * fraction * (2 - fraction * fraction)); // TODO: Move easing up the stack.\n this.gradients[id].children[0].setAttribute(\n \"stop-color\",\n this.originalColors[fromCur],\n );\n this.gradients[id].children[1].setAttribute(\n \"stop-color\",\n this.originalColors[fromCur],\n );\n this.gradients[id].children[1].setAttribute(\n \"offset\",\n `${Math.max(easedBackwardsPercent - 5, 0)}%`,\n );\n this.gradients[id].children[2].setAttribute(\n \"offset\",\n `${Math.max(easedBackwardsPercent - 5, 0)}%`,\n );\n this.gradients[id].children[3].setAttribute(\n \"offset\",\n `${easedBackwardsPercent}%`,\n );\n this.gradients[id].children[4].setAttribute(\n \"offset\",\n `${easedBackwardsPercent}%`,\n );\n this.gradients[id].children[4].setAttribute(\n \"stop-color\",\n this.originalColors[fromNext],\n );\n this.gradients[id].children[5].setAttribute(\n \"stop-color\",\n this.originalColors[fromNext],\n );\n } else {\n singleColor = true; // TODO: Avoid redundant work during move.\n }\n if (singleColor) {\n this.gradients[id].children[0].setAttribute(\n \"stop-color\",\n this.originalColors[fromCur],\n );\n this.gradients[id].children[1].setAttribute(\n \"stop-color\",\n this.originalColors[fromCur],\n );\n this.gradients[id].children[1].setAttribute(\"offset\", `100%`);\n this.gradients[id].children[2].setAttribute(\"offset\", `100%`);\n this.gradients[id].children[3].setAttribute(\"offset\", `100%`);\n this.gradients[id].children[4].setAttribute(\"offset\", `100%`);\n }\n // this.gradients[id]\n // this.elementByID(id).style.fill = this.originalColors[from];\n }\n }\n }\n }\n\n private newGradient(id: string, originalColor: string): SVGGradientElement {\n const grad = document.createElementNS(\n xmlns,\n \"radialGradient\",\n ) as SVGGradientElement;\n grad.setAttribute(\"id\", `grad-${this.svgID}-${id}`);\n grad.setAttribute(\"r\", `70.7107%`); // TODO: Adapt to puzzle.\n const stopDefs = [\n { offset: 0, color: originalColor },\n { offset: 0, color: originalColor },\n { offset: 0, color: \"black\" },\n { offset: 0, color: \"black\" },\n { offset: 0, color: originalColor },\n { offset: 100, color: originalColor },\n ];\n for (const stopDef of stopDefs) {\n const stop = document.createElementNS(xmlns, \"stop\");\n stop.setAttribute(\"offset\", `${stopDef.offset}%`);\n stop.setAttribute(\"stop-color\", stopDef.color);\n stop.setAttribute(\"stop-opacity\", \"1\");\n grad.appendChild(stop);\n }\n return grad;\n }\n\n private elementID(\n orbitName: string,\n idx: number,\n orientation: number,\n ): string {\n return orbitName + \"-l\" + idx + \"-o\" + orientation;\n }\n\n private elementByID(id: string): HTMLElement {\n // TODO: Use classes and scope selector to SVG element.\n return this.element.querySelector(\"#\" + id) as HTMLElement;\n }\n}\n", "import type { PuzzleLoader } from \"../../../puzzles/PuzzleLoader\";\nimport type { PuzzleAppearance } from \"../../../puzzles/stickerings/appearance\";\nimport {\n Direction,\n PositionListener,\n PuzzlePosition,\n} from \"../../controllers/AnimationTypes\";\nimport { RenderScheduler } from \"../../controllers/RenderScheduler\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { FreshListenerManager } from \"../../model/props/TwistyProp\";\nimport { twisty2DSVGCSS } from \"./Twisty2DPuzzle.css\";\nimport type { ExperimentalStickering, PuzzleID } from \"../..\";\nimport type { KPuzzle } from \"../../../kpuzzle\";\nimport { KPuzzleSVGWrapper } from \"./KPuzzleSVGWrapper\";\n\nexport interface Twisty2DPuzzleOptions {\n experimentalStickering?: ExperimentalStickering;\n}\n\n// <twisty-2d-svg>\nexport class Twisty2DPuzzle\n extends ManagedCustomElement\n implements PositionListener\n{\n public svg: KPuzzleSVGWrapper;\n private scheduler = new RenderScheduler(this.render.bind(this));\n #cachedPosition: PuzzlePosition | null = null; // TODO: pull when needed.\n constructor(\n private model?: TwistyPlayerModel,\n private kpuzzle?: KPuzzle,\n private svgSource?: string,\n private options?: Twisty2DPuzzleOptions,\n private puzzleLoader?: PuzzleLoader,\n ) {\n super();\n this.addCSS(twisty2DSVGCSS);\n\n this.resetSVG(); // TODO: do this in `connectedCallback()`?\n\n this.#freshListenerManager.addListener(\n this.model!.puzzleID,\n (puzzleID: PuzzleID) => {\n if (puzzleLoader?.id !== puzzleID) {\n this.disconnect();\n }\n },\n );\n\n this.#freshListenerManager.addListener(\n this.model!.legacyPosition,\n this.onPositionChange.bind(this),\n );\n\n if (this.options?.experimentalStickering) {\n this.experimentalSetStickering(this.options.experimentalStickering);\n }\n }\n\n #freshListenerManager = new FreshListenerManager();\n disconnect(): void {\n this.#freshListenerManager.disconnect();\n }\n\n onPositionChange(position: PuzzlePosition): void {\n try {\n if (position.movesInProgress.length > 0) {\n const move = position.movesInProgress[0].move;\n\n let partialMove = move;\n if (position.movesInProgress[0].direction === Direction.Backwards) {\n partialMove = move.invert();\n }\n const newState = position.state.applyMove(partialMove);\n // TODO: move to render()\n this.svg.draw(\n position.state,\n newState,\n position.movesInProgress[0].fraction,\n );\n } else {\n this.svg.draw(position.state);\n this.#cachedPosition = position;\n }\n } catch (e) {\n console.warn(\n \"Bad position (this doesn't necessarily mean something is wrong). Pre-emptively disconnecting:\",\n this.puzzleLoader?.id,\n e,\n );\n this.disconnect();\n }\n }\n\n scheduleRender(): void {\n this.scheduler.requestAnimFrame();\n }\n\n experimentalSetStickering(stickering: ExperimentalStickering): void {\n (async () => {\n if (!this.puzzleLoader?.appearance) {\n return;\n }\n const appearance = await this.puzzleLoader.appearance(stickering);\n this.resetSVG(appearance);\n })();\n }\n\n // TODO: do this without constructing a new SVG.\n private resetSVG(appearance?: PuzzleAppearance): void {\n if (this.svg) {\n this.removeElement(this.svg.element);\n }\n if (!this.kpuzzle) {\n return; // TODO\n }\n this.svg = new KPuzzleSVGWrapper(this.kpuzzle, this.svgSource!, appearance); // TODO\n this.addElement(this.svg.element);\n if (this.#cachedPosition) {\n this.onPositionChange(this.#cachedPosition);\n }\n }\n\n private render(): void {\n /*...*/\n }\n}\n\ncustomElementsShim.define(\"twisty-2d-puzzle\", Twisty2DPuzzle);\n", "import type { PuzzleLoader } from \"../../../puzzles\";\nimport type { ExperimentalStickering } from \"../../../twisty\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { FreshListenerManager } from \"../../model/props/TwistyProp\";\nimport type { Schedulable } from \"../../controllers/RenderScheduler\";\nimport { Twisty2DPuzzle } from \"./Twisty2DPuzzle\";\n\nexport class Twisty2DPuzzleWrapper implements Schedulable {\n constructor(\n private model: TwistyPlayerModel,\n public schedulable: Schedulable,\n private puzzleLoader: PuzzleLoader,\n private effectiveVisualization: \"2D\" | \"experimental-2D-LL\",\n ) {\n this.twisty2DPuzzle(); // Start constructing.\n\n this.#freshListenerManager.addListener(\n this.model.twistySceneModel.stickering,\n async (stickering: ExperimentalStickering) => {\n (await this.twisty2DPuzzle()).experimentalSetStickering(stickering);\n },\n );\n }\n\n #freshListenerManager = new FreshListenerManager();\n disconnect(): void {\n this.#freshListenerManager.disconnect();\n }\n\n // TODO: Hook this up nicely.\n scheduleRender(): void {\n // Nothing\n }\n\n #cachedTwisty2DPuzzle: Promise<Twisty2DPuzzle> | null = null;\n // TODO: Stale dropper?\n async twisty2DPuzzle(): Promise<Twisty2DPuzzle> {\n return (this.#cachedTwisty2DPuzzle ??= (async () => {\n const svgPromise =\n this.effectiveVisualization === \"experimental-2D-LL\"\n ? this.puzzleLoader.llSVG!()\n : this.puzzleLoader.svg();\n return new Twisty2DPuzzle(\n this.model,\n await this.puzzleLoader.kpuzzle(),\n await svgPromise,\n {},\n this.puzzleLoader,\n );\n })());\n }\n}\n", "import type { Scene as ThreeScene } from \"three\";\nimport type { PuzzleLoader } from \"../../../puzzles\";\nimport type { Schedulable } from \"../../controllers/RenderScheduler\";\nimport { THREEJS } from \"../../heavy-code-imports/3d\";\nimport { FreshListenerManager } from \"../../model/props/TwistyProp\";\nimport type { TwistySceneModel } from \"../../model/TwistySceneModel\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { twistyViewerWrapperCSS } from \"../TwistyViewerWrapper.css\";\nimport { Twisty2DPuzzleWrapper } from \"./Twisty2DPuzzleWrapper\";\n\nexport class Twisty2DSceneWrapper\n extends ManagedCustomElement\n implements Schedulable\n{\n #freshListenerManager = new FreshListenerManager();\n disconnect(): void {\n this.#freshListenerManager.disconnect();\n }\n\n constructor(\n public model?: TwistySceneModel,\n private effectiveVisualization?: \"2D\" | \"experimental-2D-LL\",\n ) {\n super();\n }\n\n async connectedCallback(): Promise<void> {\n this.addCSS(twistyViewerWrapperCSS);\n if (this.model) {\n this.#freshListenerManager.addListener(\n this.model.twistyPlayerModel.puzzleLoader,\n this.onPuzzleLoader.bind(this),\n );\n }\n }\n\n #cachedScene: Promise<ThreeScene> | null;\n async scene(): Promise<ThreeScene> {\n return (this.#cachedScene ??= (async () => new (await THREEJS).Scene())());\n }\n\n scheduleRender(): void {\n this.#currentTwisty2DPuzzleWrapper?.scheduleRender();\n }\n\n #currentTwisty2DPuzzleWrapper: Twisty2DPuzzleWrapper | null = null;\n currentTwisty2DPuzzleWrapper(): Twisty2DPuzzleWrapper | null {\n return this.#currentTwisty2DPuzzleWrapper;\n }\n\n // #oldTwisty3DPuzzleWrappers: Twisty3DPuzzleWrapper[] = []; // TODO: Animate these out.\n async setCurrentTwisty2DPuzzleWrapper(\n twisty2DPuzzleWrapper: Twisty2DPuzzleWrapper,\n ): Promise<void> {\n const old = this.#currentTwisty2DPuzzleWrapper;\n this.#currentTwisty2DPuzzleWrapper = twisty2DPuzzleWrapper;\n old?.disconnect(); // TODO: Disconnect properly.\n const twisty2DPuzzlePromise = twisty2DPuzzleWrapper.twisty2DPuzzle();\n this.contentWrapper.textContent = \"\"; // Clear existing ones.\n this.addElement(await twisty2DPuzzlePromise);\n }\n\n async onPuzzleLoader(puzzleLoader: PuzzleLoader): Promise<void> {\n this.#currentTwisty2DPuzzleWrapper?.disconnect();\n const twisty2DPuzzleWrapper = new Twisty2DPuzzleWrapper(\n this.model!.twistyPlayerModel,\n this,\n puzzleLoader,\n this.effectiveVisualization!,\n );\n\n this.setCurrentTwisty2DPuzzleWrapper(twisty2DPuzzleWrapper);\n }\n}\n\ncustomElementsShim.define(\"twisty-2d-scene-wrapper\", Twisty2DSceneWrapper);\n", "import type { ManagedCustomElement } from \"./ManagedCustomElement\";\n\nexport class ClassListManager<SuffixType extends string> {\n #currentClassName: string | null = null;\n // The prefix should ideally end in a dash.\n constructor(\n private elem: ManagedCustomElement,\n private prefix: string,\n private validSuffixes: SuffixType[],\n ) {}\n\n // Does nothing if there was no value.\n clearValue(): void {\n if (this.#currentClassName) {\n this.elem.contentWrapper.classList.remove(this.#currentClassName);\n }\n this.#currentClassName = null; // TODO: add test for this behaviour.\n }\n\n // Returns if the value changed\n setValue(suffix: SuffixType): boolean {\n if (!this.validSuffixes.includes(suffix)) {\n throw new Error(`Invalid suffix: ${suffix}`);\n }\n const newClassName = `${this.prefix}${suffix}`;\n const changed = this.#currentClassName !== newClassName;\n if (changed) {\n this.clearValue();\n this.elem.contentWrapper.classList.add(newClassName);\n this.#currentClassName = newClassName;\n }\n return changed;\n }\n}\n", "import type { Raycaster, Texture as ThreeTexture } from \"three\";\nimport { experimentalCubeAppearance, PuzzleLoader } from \"../../../puzzles\";\nimport type { ExperimentalStickering } from \"../../../twisty\";\nimport { proxy3D } from \"../../heavy-code-imports/3d\";\nimport type { FoundationDisplay } from \"../../model/props/puzzle/display/FoundationDisplayProp\";\nimport type { HintFaceletStyleWithAuto } from \"../../model/props/puzzle/display/HintFaceletProp\";\nimport { FreshListenerManager } from \"../../model/props/TwistyProp\";\nimport type { VisualizationStrategy } from \"../../model/props/viewer/VisualizationStrategyProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport type { PuzzlePosition } from \"../../controllers/AnimationTypes\";\nimport type { Schedulable } from \"../../controllers/RenderScheduler\";\nimport type { Twisty3DPuzzle } from \"./puzzles/Twisty3DPuzzle\";\nimport type { Cube3D } from \"./puzzles/Cube3D\";\nimport type { PG3D } from \"./puzzles/PG3D\";\n\nexport class Twisty3DPuzzleWrapper implements Schedulable {\n constructor(\n private model: TwistyPlayerModel,\n public schedulable: Schedulable,\n private puzzleLoader: PuzzleLoader,\n private visualizationStrategy: VisualizationStrategy,\n ) {\n this.twisty3DPuzzle(); // Start constructing.\n\n // TODO: Hook up listeners before loading the heavy code in the async constructor, so we get any intermediate updates?\n // Repro: Switch to 40x40x40 a fraction of a second before animation finishes. When it's loaded the itmeline is at the end, but the 40x40x40 is rendered with an earlier position.\n\n this.#freshListenerManager.addListener(\n this.model.puzzleLoader,\n (puzzleLoader: PuzzleLoader) => {\n if (this.puzzleLoader.id !== puzzleLoader.id) {\n this.disconnect();\n }\n },\n );\n this.#freshListenerManager.addListener(\n this.model.legacyPosition,\n async (position: PuzzlePosition) => {\n try {\n (await this.twisty3DPuzzle()).onPositionChange(position);\n this.scheduleRender();\n } catch (e) {\n // TODO\n // console.warn(\n // \"Bad position (this doesn't necessarily mean something is wrong). Pre-emptively disconnecting:\",\n // this.puzzleLoader.id,\n // e,\n // );\n this.disconnect();\n }\n },\n );\n\n this.#freshListenerManager.addListener(\n this.model.twistySceneModel.hintFacelet,\n async (hintFaceletStyle: HintFaceletStyleWithAuto) => {\n (\n (await this.twisty3DPuzzle()) as Cube3D | PG3D\n ).experimentalUpdateOptions({\n hintFacelets:\n hintFaceletStyle === \"auto\" ? \"floating\" : hintFaceletStyle,\n });\n this.scheduleRender();\n },\n );\n this.#freshListenerManager.addListener(\n this.model.twistySceneModel.foundationDisplay,\n async (foundationDisplay: FoundationDisplay) => {\n (\n (await this.twisty3DPuzzle()) as Cube3D | PG3D\n ).experimentalUpdateOptions({\n showFoundation: foundationDisplay !== \"none\",\n });\n this.scheduleRender();\n },\n );\n this.#freshListenerManager.addListener(\n this.model.twistySceneModel.stickering,\n async (stickering: ExperimentalStickering) => {\n if (\"setStickering\" in (await this.twisty3DPuzzle())) {\n ((await this.twisty3DPuzzle()) as Cube3D).setStickering(stickering);\n this.scheduleRender();\n } else {\n if (\n [\n \"experimental-global-custom-1\",\n \"experimental-global-custom-2\",\n ].includes(stickering)\n ) {\n const [twisty3D] = await Promise.all([this.twisty3DPuzzle()]);\n (twisty3D as PG3D).experimentalSetAppearance(\n await experimentalCubeAppearance(this.puzzleLoader, stickering),\n );\n this.scheduleRender();\n return;\n }\n\n // TODO: create a prop to handle this.\n if (\"appearance\" in this.puzzleLoader) {\n const [twisty3D, appearancePromise] = await Promise.all([\n this.twisty3DPuzzle(),\n this.puzzleLoader.appearance!(stickering ?? \"full\"),\n ]);\n (twisty3D as PG3D).experimentalSetAppearance(appearancePromise);\n this.scheduleRender();\n }\n }\n },\n );\n\n this.#freshListenerManager.addMultiListener(\n [\n this.model.twistySceneModel.foundationStickerSprite,\n this.model.twistySceneModel.hintStickerSprite,\n ],\n async (\n inputs: [\n foundationSprite: ThreeTexture | null,\n hintSprite: ThreeTexture | null,\n ],\n ) => {\n if (\"experimentalUpdateTexture\" in (await this.twisty3DPuzzle())) {\n ((await this.twisty3DPuzzle()) as PG3D).experimentalUpdateTexture(\n true,\n ...inputs,\n );\n this.scheduleRender();\n }\n },\n );\n }\n\n #freshListenerManager = new FreshListenerManager();\n disconnect(): void {\n this.#freshListenerManager.disconnect();\n }\n\n scheduleRender(): void {\n this.schedulable.scheduleRender();\n }\n\n #cachedTwisty3DPuzzle: Promise<Twisty3DPuzzle> | null = null;\n async twisty3DPuzzle(): Promise<Twisty3DPuzzle> {\n return (this.#cachedTwisty3DPuzzle ??= (async () => {\n const proxyPromise = proxy3D();\n if (\n this.puzzleLoader.id === \"3x3x3\" &&\n this.visualizationStrategy === \"Cube3D\"\n ) {\n // TODO: synchronize\n const [foundationSprite, hintSprite, experimentalStickering] =\n await Promise.all([\n this.model.twistySceneModel.foundationStickerSprite.get(),\n this.model.twistySceneModel.hintStickerSprite.get(),\n this.model.twistySceneModel.stickering.get(),\n ]);\n return (await proxyPromise).cube3DShim({\n foundationSprite,\n hintSprite,\n experimentalStickering,\n });\n } else {\n const [hintFacelets, foundationSprite, hintSprite] = await Promise.all([\n this.model.twistySceneModel.hintFacelet.get(),\n this.model.twistySceneModel.foundationStickerSprite.get(),\n this.model.twistySceneModel.hintStickerSprite.get(),\n ]);\n const pg3d = (await proxyPromise).pg3dShim(\n this.puzzleLoader,\n hintFacelets === \"auto\" ? \"floating\" : hintFacelets,\n );\n // TODO: Figure out how to do this in one place using the listener.\n pg3d.then((p) =>\n p.experimentalUpdateTexture(\n true,\n foundationSprite ?? undefined,\n hintSprite ?? undefined,\n ),\n );\n return pg3d;\n }\n })());\n }\n\n async raycastMove(\n raycasterPromise: Promise<Raycaster>,\n transformations: {\n invert: boolean;\n depth?: \"secondSlice\" | \"rotation\" | \"none\";\n },\n ): Promise<void> {\n const puzzle = (await this.twisty3DPuzzle()) as Cube3D | PG3D;\n // TODO: check this differently.\n if (!(\"experimentalGetControlTargets\" in puzzle)) {\n console.info(\"not PG3D! skipping raycast\");\n return;\n }\n\n const targets = puzzle.experimentalGetControlTargets(); // TODO: sticker targets\n const [raycaster] = await Promise.all([raycasterPromise]);\n\n const intersects = raycaster.intersectObjects(targets);\n if (intersects.length > 0) {\n const closestMove = puzzle.getClosestMoveToAxis(\n intersects[0].point,\n transformations,\n );\n if (closestMove) {\n this.model.experimentalAddMove(closestMove.move, {\n coalesce: true,\n mod: closestMove.order,\n });\n } else {\n console.info(\"Skipping move!\");\n }\n }\n }\n}\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,\n HEIGHT = 48 * PR,\n TEXT_X = 3 * PR,\n TEXT_Y = 2 * PR,\n GRAPH_X = 3 * PR,\n GRAPH_Y = 15 * PR,\n GRAPH_WIDTH = 74 * PR,\n 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(private name: string, private fg: string, private bg: string) {\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) +\n \" \" +\n this.name +\n \" (\" +\n Math.round(this.min) +\n \"-\" +\n Math.round(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", "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", "import { CSSSource } from \"../ManagedCustomElement\";\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\nexport const twisty3DVantageCSS = new CSSSource(`\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", "// 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 insteadl.\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) => {\n e.preventDefault();\n });\n // Prevent touch scrolling (preventing default on `pointermove` doesn't work).\n this.addTargetListener(\"touchmove\", (e) => e.preventDefault());\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) => e.preventDefault());\n }\n\n // Idempotent\n stop(): void {\n for (const [eventType, listener] of this.#targetListeners.entries()) {\n this.target.removeEventListener(eventType, listener);\n }\n this.#targetListeners.clear();\n this.#lazyListenersRegistered = false;\n }\n\n #targetListeners = new Map<string, (e: MouseEvent) => any>();\n addTargetListener(eventType: string, listener: (e: MouseEvent) => any) {\n if (!this.#targetListeners.has(eventType)) {\n this.target.addEventListener(eventType, listener);\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 { THREEJS } from \"../../heavy-code-imports/3d\";\nimport type { Camera, Scene, WebGLRenderer } from \"three\";\nimport { pixelRatio } from \"../canvas\";\n\nconst renderers: Promise<WebGLRenderer>[] = [];\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 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 // 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(renderer.domElement, 0, 0);\n}\n\nexport async function newRenderer(): Promise<WebGLRenderer> {\n const rendererConstructor = (await THREEJS).WebGLRenderer;\n const renderer = new rendererConstructor({\n antialias: true,\n alpha: true,\n });\n renderer.setPixelRatio(pixelRatio());\n return renderer;\n}\n", "import type { Vector3 } from \"three\";\nimport { RenderScheduler } from \"../../controllers/RenderScheduler\";\nimport { THREEJS } 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 THREEJS).Spherical();\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(\"move\", this.onMove.bind(this));\n this.dragTracker.addEventListener(\"up\", this.onUp.bind(this));\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 (\n e.detail.attachedInfo as TwistyOrbitControlsDragAttachedInfo\n ).lastTemperedX,\n (\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\";\nimport { Stats } from \"../../../vendor/three/examples/jsm/libs/stats.modified.module\";\nimport { THREEJS } from \"../../heavy-code-imports/3d\";\nimport { StaleDropper } from \"../../model/PromiseFreshener\";\nimport type { TwistyPropParent } from \"../../model/props/TwistyProp\";\nimport type { OrbitCoordinates } from \"../../model/props/viewer/OrbitCoordinatesRequestProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { RenderScheduler } from \"../../controllers/RenderScheduler\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { pixelRatio } from \"../canvas\";\nimport { twisty3DVantageCSS } from \"./Twisty3DVantage.css\";\nimport { DragTracker, PressInfo } from \"./DragTracker\";\nimport { newRenderer, renderPooled } from \"./RendererPool\";\nimport { DEGREES_PER_RADIAN } from \"./TAU\";\nimport type { Twisty3DSceneWrapper } from \"./Twisty3DSceneWrapper\";\nimport { TwistyOrbitControls } from \"./TwistyOrbitControls\";\nimport type { DragInputMode } from \"../../model/props/puzzle/state/DragInputProp\";\n\nlet SHOW_STATS = false;\nexport function debugShowRenderStats(enable: boolean): void {\n SHOW_STATS = enable;\n}\n\nexport async function setCameraFromOrbitCoordinates(\n camera: PerspectiveCamera,\n orbitCoordinates: OrbitCoordinates,\n backView: boolean = false,\n): Promise<void> {\n const spherical = new (await THREEJS).Spherical(\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 shareAllNewRenderers: boolean | null = null;\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// - true: Force all new (i.e. constructed in the future) renderers to be shared\n// - false: Force all new (i.e. constructed in the future) renderers to be dedicated\n// - null: Reset to the default heuristics.\nexport function experimentalForceNewRendererSharing(\n share: boolean | null,\n): void {\n shareAllNewRenderers = share;\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).\nfunction shareRenderer(): boolean {\n if (shareAllNewRenderers !== null) {\n if (!shareAllNewRenderers) {\n dedicatedRenderersSoFar++;\n }\n return shareAllNewRenderers;\n }\n if (dedicatedRenderersSoFar < DEFAULT_MAX_DEDICATED_RENDERERS) {\n dedicatedRenderersSoFar++;\n return false;\n } else {\n return true;\n }\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 (SHOW_STATS) {\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(\"press\", 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 });\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();\n canvasInfo.canvas.style.height = h.toString();\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 case \"none\":\n dragTracker.stop();\n break;\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 THREEJS).PerspectiveCamera(\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 THREEJS).Vector3(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 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 }\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", "import type { PerspectiveCamera, Scene as ThreeScene } from \"three\";\nimport type { PuzzleLoader } from \"../../../puzzles\";\nimport type { Schedulable } from \"../../controllers/RenderScheduler\";\nimport { THREEJS } from \"../../heavy-code-imports/3d\";\nimport { StaleDropper } from \"../../model/PromiseFreshener\";\nimport { FreshListenerManager } from \"../../model/props/TwistyProp\";\nimport type {\n BackViewLayout,\n BackViewLayoutWithAuto,\n} from \"../../model/props/viewer/BackViewProp\";\nimport type { VisualizationStrategy } from \"../../model/props/viewer/VisualizationStrategyProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { ClassListManager } from \"../ClassListManager\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { twistyViewerWrapperCSS } from \"../TwistyViewerWrapper.css\";\nimport type { PressInfo } from \"./DragTracker\";\nimport { Twisty3DPuzzleWrapper } from \"./Twisty3DPuzzleWrapper\";\nimport { Twisty3DVantage } from \"./Twisty3DVantage\";\n\nexport class Twisty3DSceneWrapper\n extends ManagedCustomElement\n implements Schedulable\n{\n #backViewClassListManager: ClassListManager<BackViewLayoutWithAuto> =\n new ClassListManager(this, \"back-view-\", [\n \"auto\",\n \"none\",\n \"side-by-side\",\n \"top-right\",\n ]);\n\n #freshListenerManager = new FreshListenerManager();\n disconnect(): void {\n this.#freshListenerManager.disconnect();\n }\n\n constructor(public model?: TwistyPlayerModel) {\n super();\n }\n\n async connectedCallback(): Promise<void> {\n this.addCSS(twistyViewerWrapperCSS);\n const vantage = new Twisty3DVantage(this.model, this);\n this.addVantage(vantage);\n if (this.model) {\n this.#freshListenerManager.addMultiListener(\n [this.model.puzzleLoader, this.model.visualizationStrategy],\n this.onPuzzle.bind(this),\n );\n this.#freshListenerManager.addListener(\n this.model.backView,\n this.onBackView.bind(this),\n );\n }\n this.scheduleRender();\n }\n\n #backViewVantage: Twisty3DVantage | null = null;\n setBackView(backView: BackViewLayout): void {\n const shouldHaveBackView = [\"side-by-side\", \"top-right\"].includes(backView);\n const hasBackView = this.#backViewVantage !== null;\n\n this.#backViewClassListManager.setValue(backView);\n if (shouldHaveBackView) {\n if (!hasBackView) {\n this.#backViewVantage = new Twisty3DVantage(this.model, this, {\n backView: true,\n });\n this.addVantage(this.#backViewVantage);\n this.scheduleRender();\n }\n } else {\n if (this.#backViewVantage) {\n this.removeVantage(this.#backViewVantage);\n this.#backViewVantage = null;\n }\n }\n }\n\n onBackView(backView: BackViewLayout): void {\n this.setBackView(backView);\n }\n\n async onPress(\n e: CustomEvent<{\n pressInfo: PressInfo;\n cameraPromise: Promise<PerspectiveCamera>;\n }>,\n ): Promise<void> {\n const twisty3DPuzzleWrapper = this.#currentTwisty3DPuzzleWrapper;\n if (!twisty3DPuzzleWrapper) {\n console.info(\"no wrapper; skipping scene wrapper press!\");\n return;\n }\n\n const raycasterPromise = (async () => {\n const [camera, three] = await Promise.all([\n e.detail.cameraPromise,\n THREEJS,\n ]);\n\n const raycaster = new three.Raycaster();\n const mouse = new (await THREEJS).Vector2(\n e.detail.pressInfo.normalizedX,\n e.detail.pressInfo.normalizedY,\n );\n raycaster.setFromCamera(mouse, camera);\n return raycaster;\n })();\n\n twisty3DPuzzleWrapper.raycastMove(raycasterPromise, {\n invert: !e.detail.pressInfo.rightClick,\n depth: e.detail.pressInfo.keys.ctrlOrMetaKey\n ? \"rotation\"\n : e.detail.pressInfo.keys.shiftKey\n ? \"secondSlice\"\n : \"none\",\n });\n }\n\n #cachedScene: Promise<ThreeScene> | null;\n async scene(): Promise<ThreeScene> {\n return (this.#cachedScene ??= (async () => new (await THREEJS).Scene())());\n }\n\n #vantages: Set<Twisty3DVantage> = new Set();\n addVantage(vantage: Twisty3DVantage) {\n vantage.addEventListener(\"press\", this.onPress.bind(this));\n this.#vantages.add(vantage);\n this.contentWrapper.appendChild(vantage);\n }\n\n removeVantage(vantage: Twisty3DVantage) {\n this.#vantages.delete(vantage);\n vantage.remove();\n vantage.disconnect();\n this.#currentTwisty3DPuzzleWrapper?.disconnect();\n }\n\n experimentalVantages(): Iterable<Twisty3DVantage> {\n return this.#vantages.values();\n }\n\n scheduleRender(): void {\n for (const vantage of this.#vantages) {\n vantage.scheduleRender();\n }\n }\n\n #currentTwisty3DPuzzleWrapper: Twisty3DPuzzleWrapper | null = null;\n // #oldTwisty3DPuzzleWrappers: Twisty3DPuzzleWrapper[] = []; // TODO: Animate these out.\n async setCurrentTwisty3DPuzzleWrapper(\n scene: ThreeScene,\n twisty3DPuzzleWrapper: Twisty3DPuzzleWrapper,\n ): Promise<void> {\n const old = this.#currentTwisty3DPuzzleWrapper;\n try {\n this.#currentTwisty3DPuzzleWrapper = twisty3DPuzzleWrapper;\n old?.disconnect();\n scene.add(await twisty3DPuzzleWrapper.twisty3DPuzzle());\n } finally {\n if (old) {\n // We wait for the new puzzle to be in place before removing the old one.\n scene.remove(await old.twisty3DPuzzle());\n }\n }\n }\n\n #twisty3DStaleDropper: StaleDropper<[ThreeScene, Twisty3DPuzzleWrapper]> =\n new StaleDropper<[ThreeScene, Twisty3DPuzzleWrapper]>();\n\n async onPuzzle(\n inputs: [\n puzzleLoader: PuzzleLoader,\n visualizationStrategy: VisualizationStrategy,\n ],\n ): Promise<void> {\n if (inputs[1] === \"2D\") {\n // We are being asked to render with stale info. Ignore.\n return;\n }\n this.#currentTwisty3DPuzzleWrapper?.disconnect();\n const [scene, twisty3DPuzzleWrapper] =\n await this.#twisty3DStaleDropper.queue(\n Promise.all([\n this.scene(),\n new Twisty3DPuzzleWrapper(this.model!, this, inputs[0], inputs[1]), // TODO\n ]),\n );\n\n this.setCurrentTwisty3DPuzzleWrapper(scene, twisty3DPuzzleWrapper);\n }\n}\n\ncustomElementsShim.define(\"twisty-3d-scene-wrapper\", Twisty3DSceneWrapper);\n", "import { CSSSource } from \"../ManagedCustomElement\";\n\nexport const buttonGridCSS = new CSSSource(`\n:host {\n width: 384px;\n height: 24px;\n display: grid;\n}\n\n.wrapper {\n width: 100%;\n height: 100%;\n display: grid;\n overflow: hidden;\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n}\n\n.wrapper {\n grid-auto-flow: column;\n}\n\n.viewer-link-none .twizzle-link-button {\n display: none;\n}\n\n.wrapper twisty-button,\n.wrapper twisty-control-button {\n width: inherit;\n height: inherit;\n}\n`);\n\nexport const buttonCSS = new CSSSource(`\n:host:not([hidden]) {\n display: grid;\n}\n\n:host {\n width: 48px;\n height: 24px;\n}\n\n.wrapper {\n width: 100%;\n height: 100%;\n}\n\nbutton {\n width: 100%;\n height: 100%;\n border: none;\n \n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n\n background-color: rgba(196, 196, 196, 0.75);\n}\n\nbutton:enabled {\n background-color: rgba(196, 196, 196, 0.75)\n}\n\nbutton:disabled {\n background-color: rgba(0, 0, 0, 0.4);\n opacity: 0.25;\n pointer-events: none;\n}\n\nbutton:enabled:hover {\n background-color: rgba(255, 255, 255, 0.75);\n box-shadow: 0 0 1em rgba(0, 0, 0, 0.25);\n cursor: pointer;\n}\n\n/* TODO: fullscreen icons have too much padding?? */\n.svg-skip-to-start button,\nbutton.svg-skip-to-start {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik0yNjQzIDEwMzdxMTktMTkgMzItMTN0MTMgMzJ2MTQ3MnEwIDI2LTEzIDMydC0zMi0xM2wtNzEwLTcxMHEtOS05LTEzLTE5djcxMHEwIDI2LTEzIDMydC0zMi0xM2wtNzEwLTcxMHEtOS05LTEzLTE5djY3OHEwIDI2LTE5IDQ1dC00NSAxOUg5NjBxLTI2IDAtNDUtMTl0LTE5LTQ1VjEwODhxMC0yNiAxOS00NXQ0NS0xOWgxMjhxMjYgMCA0NSAxOXQxOSA0NXY2NzhxNC0xMSAxMy0xOWw3MTAtNzEwcTE5LTE5IDMyLTEzdDEzIDMydjcxMHE0LTExIDEzLTE5eiIvPjwvc3ZnPg==\");\n}\n\n.svg-skip-to-end button,\nbutton.svg-skip-to-end {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik05NDEgMjU0N3EtMTkgMTktMzIgMTN0LTEzLTMyVjEwNTZxMC0yNiAxMy0zMnQzMiAxM2w3MTAgNzEwcTggOCAxMyAxOXYtNzEwcTAtMjYgMTMtMzJ0MzIgMTNsNzEwIDcxMHE4IDggMTMgMTl2LTY3OHEwLTI2IDE5LTQ1dDQ1LTE5aDEyOHEyNiAwIDQ1IDE5dDE5IDQ1djE0MDhxMCAyNi0xOSA0NXQtNDUgMTloLTEyOHEtMjYgMC00NS0xOXQtMTktNDV2LTY3OHEtNSAxMC0xMyAxOWwtNzEwIDcxMHEtMTkgMTktMzIgMTN0LTEzLTMydi03MTBxLTUgMTAtMTMgMTl6Ii8+PC9zdmc+\");\n}\n\n.svg-step-forward button,\nbutton.svg-step-forward {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik0yNjg4IDE1NjhxMCAyNi0xOSA0NWwtNTEyIDUxMnEtMTkgMTktNDUgMTl0LTQ1LTE5cS0xOS0xOS0xOS00NXYtMjU2aC0yMjRxLTk4IDAtMTc1LjUgNnQtMTU0IDIxLjVxLTc2LjUgMTUuNS0xMzMgNDIuNXQtMTA1LjUgNjkuNXEtNDkgNDIuNS04MCAxMDF0LTQ4LjUgMTM4LjVxLTE3LjUgODAtMTcuNSAxODEgMCA1NSA1IDEyMyAwIDYgMi41IDIzLjV0Mi41IDI2LjVxMCAxNS04LjUgMjV0LTIzLjUgMTBxLTE2IDAtMjgtMTctNy05LTEzLTIydC0xMy41LTMwcS03LjUtMTctMTAuNS0yNC0xMjctMjg1LTEyNy00NTEgMC0xOTkgNTMtMzMzIDE2Mi00MDMgODc1LTQwM2gyMjR2LTI1NnEwLTI2IDE5LTQ1dDQ1LTE5cTI2IDAgNDUgMTlsNTEyIDUxMnExOSAxOSAxOSA0NXoiLz48L3N2Zz4=\");\n}\n\n.svg-step-backward button,\nbutton.svg-step-backward {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik0yNjg4IDIwNDhxMCAxNjYtMTI3IDQ1MS0zIDctMTAuNSAyNHQtMTMuNSAzMHEtNiAxMy0xMyAyMi0xMiAxNy0yOCAxNy0xNSAwLTIzLjUtMTB0LTguNS0yNXEwLTkgMi41LTI2LjV0Mi41LTIzLjVxNS02OCA1LTEyMyAwLTEwMS0xNy41LTE4MXQtNDguNS0xMzguNXEtMzEtNTguNS04MC0xMDF0LTEwNS41LTY5LjVxLTU2LjUtMjctMTMzLTQyLjV0LTE1NC0yMS41cS03Ny41LTYtMTc1LjUtNmgtMjI0djI1NnEwIDI2LTE5IDQ1dC00NSAxOXEtMjYgMC00NS0xOWwtNTEyLTUxMnEtMTktMTktMTktNDV0MTktNDVsNTEyLTUxMnExOS0xOSA0NS0xOXQ0NSAxOXExOSAxOSAxOSA0NXYyNTZoMjI0cTcxMyAwIDg3NSA0MDMgNTMgMTM0IDUzIDMzM3oiLz48L3N2Zz4=\");\n}\n\n.svg-pause button,\nbutton.svg-pause {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik0yNTYwIDEwODh2MTQwOHEwIDI2LTE5IDQ1dC00NSAxOWgtNTEycS0yNiAwLTQ1LTE5dC0xOS00NVYxMDg4cTAtMjYgMTktNDV0NDUtMTloNTEycTI2IDAgNDUgMTl0MTkgNDV6bS04OTYgMHYxNDA4cTAgMjYtMTkgNDV0LTQ1IDE5aC01MTJxLTI2IDAtNDUtMTl0LTE5LTQ1VjEwODhxMC0yNiAxOS00NXQ0NS0xOWg1MTJxMjYgMCA0NSAxOXQxOSA0NXoiLz48L3N2Zz4=\");\n}\n\n.svg-play button,\nbutton.svg-play {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTg0IiBoZWlnaHQ9IjM1ODQiIHZpZXdCb3g9IjAgMCAzNTg0IDM1ODQiPjxwYXRoIGQ9Ik0yNDcyLjUgMTgyM2wtMTMyOCA3MzhxLTIzIDEzLTM5LjUgM3QtMTYuNS0zNlYxMDU2cTAtMjYgMTYuNS0zNnQzOS41IDNsMTMyOCA3MzhxMjMgMTMgMjMgMzF0LTIzIDMxeiIvPjwvc3ZnPg==\");\n}\n\n.svg-enter-fullscreen button,\nbutton.svg-enter-fullscreen {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAyOCAyOCIgd2lkdGg9IjI4Ij48cGF0aCBkPSJNMiAyaDI0djI0SDJ6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTkgMTZIN3Y1aDV2LTJIOXYtM3ptLTItNGgyVjloM1Y3SDd2NXptMTIgN2gtM3YyaDV2LTVoLTJ2M3pNMTYgN3YyaDN2M2gyVjdoLTV6Ii8+PC9zdmc+\");\n}\n\n.svg-exit-fullscreen button,\nbutton.svg-exit-fullscreen {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAyOCAyOCIgd2lkdGg9IjI4Ij48cGF0aCBkPSJNMiAyaDI0djI0SDJ6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTcgMThoM3YzaDJ2LTVIN3Yyem0zLThIN3YyaDVWN2gtMnYzem02IDExaDJ2LTNoM3YtMmgtNXY1em0yLTExVjdoLTJ2NWg1di0yaC0zeiIvPjwvc3ZnPg==\");\n}\n\n.svg-twizzle-tw button,\nbutton.svg-twizzle-tw {\n background-image: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODY0IiBoZWlnaHQ9IjYwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMzk3LjU4MSAxNTEuMTh2NTcuMDg0aC04OS43MDN2MjQwLjM1MmgtNjYuOTU1VjIwOC4yNjRIMTUxLjIydi01Ny4wODNoMjQ2LjM2MXptNTQuMzEgNzEuNjc3bDcuNTEyIDMzLjY5MmMyLjcxOCAxMi4xNiA1LjU4IDI0LjY4IDguNTg0IDM3LjU1NWEyMTgwLjc3NSAyMTgwLjc3NSAwIDAwOS40NDIgMzguODQzIDEyNjYuMyAxMjY2LjMgMCAwMDEwLjA4NiAzNy41NTVjMy43Mi0xMi41OSA3LjM2OC0yNS40NjYgMTAuOTQ1LTM4LjYyOCAzLjU3Ni0xMy4xNjIgNy4wMS0yNi4xMSAxMC4zLTM4Ljg0M2w1Ljc2OS0yMi40NTZjMS4yNDgtNC44ODcgMi40NzItOS43MDUgMy42NzQtMTQuNDU1IDMuMDA0LTExLjg3NSA1LjY1MS0yMi45NjIgNy45NC0zMy4yNjNoNDYuMzU0bDIuMzg0IDEwLjU2M2EyMDAwLjc3IDIwMDAuNzcgMCAwMDMuOTM1IDE2LjgyOGw2LjcxMSAyNy43MWMxLjIxMyA0Ljk1NiAyLjQ1IDkuOTggMy43MDkgMTUuMDczYTMxMTkuNzc3IDMxMTkuNzc3IDAgMDA5Ljg3MSAzOC44NDMgMTI0OS4yMjcgMTI0OS4yMjcgMCAwMDEwLjczIDM4LjYyOCAxOTA3LjYwNSAxOTA3LjYwNSAwIDAwMTAuMzAxLTM3LjU1NSAxMzk3Ljk0IDEzOTcuOTQgMCAwMDkuNjU3LTM4Ljg0M2w0LjQtMTkuMDQ2Yy43MTUtMy4xMyAxLjQyMS02LjIzNiAyLjExOC05LjMyMWw5LjU3Ny00Mi44OGg2Ni41MjZhMjk4OC43MTggMjk4OC43MTggMCAwMS0xOS41MjkgNjYuMzExbC01LjcyOCAxOC40ODJhMzIzNy40NiAzMjM3LjQ2IDAgMDEtMTQuMDE1IDQzLjc1MmMtNi40MzggMTkuNi0xMi43MzMgMzcuNjk4LTE4Ljg4NSA1NC4yOTRsLTMuMzA2IDguODI1Yy00Ljg4NCAxMi44OTgtOS40MzMgMjQuMjYzLTEzLjY0NyAzNC4wOTVoLTQ5Ljc4N2E4NDE3LjI4OSA4NDE3LjI4OSAwIDAxLTIxLjAzMS02NC44MDkgMTI4OC42ODYgMTI4OC42ODYgMCAwMS0xOC44ODUtNjQuODEgMTk3Mi40NDQgMTk3Mi40NDQgMCAwMS0xOC4yNCA2NC44MSAyNTc5LjQxMiAyNTc5LjQxMiAwIDAxLTIwLjM4OCA2NC44MWgtNDkuNzg3Yy00LjY4Mi0xMC45MjYtOS43Mi0yMy43NDMtMTUuMTEtMzguNDUxbC0xLjYyOS00LjQ3Yy01LjI1OC0xNC41MjEtMTAuNjgtMzAuMTkyLTE2LjI2Ni00Ny4wMTRsLTIuNDA0LTcuMjhjLTYuNDM4LTE5LjYtMTMuMDItNDAuMzQ0LTE5Ljc0My02Mi4yMzRhMjk4OC43MDcgMjk4OC43MDcgMCAwMS0xOS41MjktNjYuMzExaDY3LjM4NXoiIGZpbGw9IiM0Mjg1RjQiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==\");\n}\n`);\n\n// Sized against full-screen dimensions.\n// button.svg-twizzle-tw {\n// background-image: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzc3IiBoZWlnaHQ9IjUxMyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMzU0LjU4MSAxMDcuMTh2NTcuMDg0aC04OS43MDN2MjQwLjM1MmgtNjYuOTU1VjE2NC4yNjRIMTA4LjIydi01Ny4wODNoMjQ2LjM2MXptNTQuMzEgNzEuNjc3bDcuNTEyIDMzLjY5MmMyLjcxOCAxMi4xNiA1LjU4IDI0LjY4IDguNTg0IDM3LjU1NWEyMTgwLjc3NSAyMTgwLjc3NSAwIDAwOS40NDIgMzguODQzIDEyNjYuMyAxMjY2LjMgMCAwMDEwLjA4NiAzNy41NTVjMy43Mi0xMi41OSA3LjM2OC0yNS40NjYgMTAuOTQ1LTM4LjYyOCAzLjU3Ni0xMy4xNjIgNy4wMS0yNi4xMSAxMC4zLTM4Ljg0M2w1Ljc2OS0yMi40NTZjMS4yNDgtNC44ODcgMi40NzItOS43MDUgMy42NzQtMTQuNDU1IDMuMDA0LTExLjg3NSA1LjY1MS0yMi45NjIgNy45NC0zMy4yNjNoNDYuMzU0bDIuMzg0IDEwLjU2M2EyMDAwLjc3IDIwMDAuNzcgMCAwMDMuOTM1IDE2LjgyOGw2LjcxMSAyNy43MWMxLjIxMyA0Ljk1NiAyLjQ1IDkuOTggMy43MDkgMTUuMDczYTMxMTkuNzc3IDMxMTkuNzc3IDAgMDA5Ljg3MSAzOC44NDMgMTI0OS4yMjcgMTI0OS4yMjcgMCAwMDEwLjczIDM4LjYyOCAxOTA3LjYwNSAxOTA3LjYwNSAwIDAwMTAuMzAxLTM3LjU1NSAxMzk3Ljk0IDEzOTcuOTQgMCAwMDkuNjU3LTM4Ljg0M2w0LjQtMTkuMDQ2Yy43MTUtMy4xMyAxLjQyMS02LjIzNiAyLjExOC05LjMyMWw5LjU3Ny00Mi44OGg2Ni41MjZhMjk4OC43MTggMjk4OC43MTggMCAwMS0xOS41MjkgNjYuMzExbC01LjcyOCAxOC40ODJhMzIzNy40NiAzMjM3LjQ2IDAgMDEtMTQuMDE1IDQzLjc1MmMtNi40MzggMTkuNi0xMi43MzMgMzcuNjk4LTE4Ljg4NSA1NC4yOTRsLTMuMzA2IDguODI1Yy00Ljg4NCAxMi44OTgtOS40MzMgMjQuMjYzLTEzLjY0NyAzNC4wOTVoLTQ5Ljc4N2E4NDE3LjI4OSA4NDE3LjI4OSAwIDAxLTIxLjAzMS02NC44MDkgMTI4OC42ODYgMTI4OC42ODYgMCAwMS0xOC44ODUtNjQuODEgMTk3Mi40NDQgMTk3Mi40NDQgMCAwMS0xOC4yNCA2NC44MSAyNTc5LjQxMiAyNTc5LjQxMiAwIDAxLTIwLjM4OCA2NC44MWgtNDkuNzg3Yy00LjY4Mi0xMC45MjYtOS43Mi0yMy43NDMtMTUuMTEtMzguNDUxbC0xLjYyOS00LjQ3Yy01LjI1OC0xNC41MjEtMTAuNjgtMzAuMTkyLTE2LjI2Ni00Ny4wMTRsLTIuNDA0LTcuMjhjLTYuNDM4LTE5LjYtMTMuMDItNDAuMzQ0LTE5Ljc0My02Mi4yMzRhMjk4OC43MDcgMjk4OC43MDcgMCAwMS0xOS41MjktNjYuMzExaDY3LjM4NXoiIGZpbGw9IiM0Mjg1RjQiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==\");\n// }\n", "// Use like this:\n// const enabled = globalSafeDocument?.fullscreenEnabled;\nexport const globalSafeDocument: Document | null =\n typeof document === \"undefined\" ? null : document;\n", "// Ponyfills for prefixing in Safari.\n\nimport { globalSafeDocument } from \"../document\";\n\ndeclare global {\n interface Document {\n webkitFullscreenEnabled?: boolean;\n webkitExitFullscreen?: () => Promise<void>;\n webkitFullscreenElement?: Element | null;\n }\n\n interface Element {\n webkitRequestFullscreen: () => Promise<void>;\n }\n}\n\n// TODO: Can `webkitFullscreenEnabled` change after it's cached at page load?\nexport const fullscreenEnabled: boolean =\n globalSafeDocument?.fullscreenEnabled ||\n !!globalSafeDocument?.webkitFullscreenEnabled;\n\nexport function documentExitFullscreen(): Promise<void> {\n if (document.exitFullscreen) {\n return document.exitFullscreen();\n } else {\n return document.webkitExitFullscreen!(); // YOLO\n }\n}\n\nexport function documentFullscreenElement(): Element | null {\n if (document.fullscreenElement) {\n return document.fullscreenElement;\n } else {\n return document.webkitFullscreenElement ?? null;\n }\n}\n\nexport function requestFullscreen(element: Element): Promise<void> {\n if (element.requestFullscreen) {\n return element.requestFullscreen();\n } else {\n return element.webkitRequestFullscreen();\n }\n}\n", "import type { ButtonCommand } from \"../../../views/control-panel/TwistyButtons\";\nimport { fullscreenEnabled } from \"../../../views/control-panel/webkit-fullscreen\";\nimport type { ViewerLinkPageWithAuto } from \"./ViewerLinkProp\";\nimport type { CoarseTimelineInfo as CoarseTimelineInfo } from \"../timeline/CoarseTimelineInfoProp\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\n\nexport const buttonIcons = [\n \"skip-to-start\",\n \"skip-to-end\",\n \"step-forward\",\n \"step-backward\",\n \"pause\",\n \"play\",\n \"enter-fullscreen\",\n \"exit-fullscreen\",\n \"twizzle-tw\",\n];\nexport type ButtonIcon = typeof buttonIcons[number];\n\ninterface ButtonAppearance {\n enabled: boolean;\n icon: ButtonIcon;\n title: string;\n hidden?: boolean;\n}\nexport type ButtonAppearances = Record<ButtonCommand, ButtonAppearance>;\n\n// TODO: reduce inputs to avoid unnecessary updates.\ninterface ButtonAppearancePropInputs {\n coarseTimelineInfo: CoarseTimelineInfo;\n viewerLink: ViewerLinkPageWithAuto;\n}\n\nexport class ButtonAppearanceProp extends TwistyPropDerived<\n ButtonAppearancePropInputs,\n ButtonAppearances\n> {\n // TODO: This still seems to fire twice for play/pause?\n derive(inputs: ButtonAppearancePropInputs): ButtonAppearances {\n const buttonAppearances = {\n \"fullscreen\": {\n // TODO: Cache?// TODO: Cache?\n enabled: fullscreenEnabled,\n icon:\n // TODO: Check against the expected element?\n // TODO: This will *not* update when we enter/leave fullscreen. We need to work more closely with the controller.\n document.fullscreenElement === null\n ? \"enter-fullscreen\"\n : \"exit-fullscreen\",\n title: \"Enter fullscreen\",\n },\n \"jump-to-start\": {\n enabled: !inputs.coarseTimelineInfo.atStart,\n icon: \"skip-to-start\",\n title: \"Restart\",\n },\n \"play-step-backwards\": {\n enabled: !inputs.coarseTimelineInfo.atStart,\n icon: \"step-backward\",\n title: \"Step backward\",\n },\n \"play-pause\": {\n enabled: !(\n inputs.coarseTimelineInfo.atStart && inputs.coarseTimelineInfo.atEnd\n ),\n icon: inputs.coarseTimelineInfo.playing ? \"pause\" : \"play\",\n title: inputs.coarseTimelineInfo.playing ? \"Pause\" : \"Play\",\n },\n \"play-step\": {\n enabled: !inputs.coarseTimelineInfo.atEnd,\n icon: \"step-forward\",\n title: \"Step forward\",\n },\n \"jump-to-end\": {\n enabled: !inputs.coarseTimelineInfo.atEnd,\n icon: \"skip-to-end\",\n title: \"Skip to End\",\n },\n \"twizzle-link\": {\n enabled: true,\n icon: \"twizzle-tw\",\n title: \"View at Twizzle\",\n hidden: inputs.viewerLink === \"none\",\n },\n };\n return buttonAppearances;\n }\n}\n", "import { BoundaryType, Direction } from \"../../controllers/AnimationTypes\";\nimport { buttonCSS, buttonGridCSS } from \"./TwistyButtons.css\";\nimport { ClassListManager } from \"../ClassListManager\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport {\n ButtonAppearances,\n ButtonIcon,\n buttonIcons,\n} from \"../../model/props/viewer/ButtonAppearanceProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport type { TwistyPlayerController } from \"../../controllers/TwistyPlayerController\";\nimport {\n documentExitFullscreen,\n documentFullscreenElement,\n requestFullscreen,\n} from \"./webkit-fullscreen\";\n\nconst buttonCommands = {\n \"fullscreen\": true,\n \"jump-to-start\": true,\n \"play-step-backwards\": true,\n \"play-pause\": true,\n \"play-step\": true,\n \"jump-to-end\": true,\n \"twizzle-link\": true,\n};\n\nexport type ButtonCommand = keyof typeof buttonCommands;\n\nexport class TwistyButtons extends ManagedCustomElement {\n buttons: Record<ButtonCommand, TwistyButton> | null = null;\n\n // TODO: Privacy\n constructor(\n public model?: TwistyPlayerModel,\n public controller?: TwistyPlayerController,\n private fullscreenElement?: HTMLElement,\n ) {\n super();\n }\n\n connectedCallback(): void {\n this.addCSS(buttonGridCSS);\n const buttons: Partial<Record<ButtonCommand, TwistyButton>> = {};\n for (const command in buttonCommands) {\n const button = new TwistyButton();\n buttons[command as ButtonCommand] = button;\n // Why does this still fire with the `disabled` attribute?\n button.addEventListener(\"click\", () =>\n this.#onCommand(command as ButtonCommand),\n );\n this.addElement(button);\n }\n this.buttons = buttons as Record<ButtonCommand, TwistyButton>;\n\n this.model?.buttonAppearance.addFreshListener(this.update.bind(this));\n }\n\n #onCommand(command: ButtonCommand) {\n switch (command) {\n case \"fullscreen\":\n this.onFullscreenButton();\n break;\n case \"jump-to-start\":\n this.controller?.jumpToStart({ flash: true });\n break;\n case \"play-step-backwards\":\n this.controller?.animationController.play({\n direction: Direction.Backwards,\n untilBoundary: BoundaryType.Move,\n });\n break;\n case \"play-pause\":\n this.controller?.togglePlay();\n break;\n case \"play-step\":\n this.controller?.animationController.play({\n direction: Direction.Forwards,\n untilBoundary: BoundaryType.Move,\n });\n break;\n case \"jump-to-end\":\n this.controller?.jumpToEnd({ flash: true });\n break;\n case \"twizzle-link\":\n this.controller?.visitTwizzleLink();\n break;\n default:\n throw new Error(\"Missing command\");\n }\n }\n\n // TODO: Should we have a prop, or a way to query if we're fullscreen?\n // https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullScreen\n async onFullscreenButton(): Promise<void> {\n if (!this.fullscreenElement) {\n throw new Error(\"Attempted to go fullscreen without an element.\");\n }\n\n if (documentFullscreenElement() === this.fullscreenElement) {\n documentExitFullscreen();\n } else {\n // TODO: Propagate button info to `ButtonAppearanceProp`.\n this.buttons?.fullscreen.setIcon(\"exit-fullscreen\");\n\n requestFullscreen(this.fullscreenElement);\n\n const onFullscreen = (): void => {\n if (documentFullscreenElement() !== this.fullscreenElement) {\n this.buttons?.fullscreen.setIcon(\"enter-fullscreen\");\n window.removeEventListener(\"fullscreenchange\", onFullscreen);\n }\n };\n window.addEventListener(\"fullscreenchange\", onFullscreen);\n }\n }\n\n async update(buttonAppearances: ButtonAppearances): Promise<void> {\n // TODO: Check that we have every command?\n for (const command in buttonCommands) {\n // TODO: Why doesn't `command` have the type `ButtonCommand`?\n const button = this.buttons![command as ButtonCommand];\n // TODO: track individual changes?\n const info = buttonAppearances[command as ButtonCommand];\n button.button.disabled = !info.enabled;\n button.button.title = info.title;\n button.setIcon(info.icon);\n button.hidden = !!info.hidden;\n // button.textContent = info.icon;\n }\n }\n}\n\ncustomElementsShim.define(\"twisty-buttons\", TwistyButtons);\n\nclass TwistyButton extends ManagedCustomElement {\n button: HTMLButtonElement = document.createElement(\"button\"); // TODO: async?\n\n connectedCallback() {\n this.addCSS(buttonCSS);\n this.addElement(this.button);\n }\n\n #iconManager: ClassListManager<ButtonIcon> = new ClassListManager(\n this,\n \"svg-\",\n buttonIcons,\n );\n\n setIcon(iconName: ButtonIcon): void {\n this.#iconManager.setValue(iconName);\n }\n}\n\ncustomElementsShim.define(\"twisty-button\", TwistyButton);\n", "import { CSSSource } from \"../ManagedCustomElement\";\n\nexport const twistyScrubberCSS = new CSSSource(`\n:host {\n width: 384px;\n height: 16px;\n display: grid;\n}\n\n.wrapper {\n width: 100%;\n height: 100%;\n display: grid;\n overflow: hidden;\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n background: rgba(196, 196, 196, 0.75)\n}\n\ninput:not(:disabled) {\n cursor: ew-resize;\n}\n`);\n", "import { twistyScrubberCSS } from \"./TwistyScrubber.css\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport type { DetailedTimelineInfo } from \"../../model/props/timeline/DetailedTimelineInfoProp\";\nimport type { TwistyPlayerModel } from \"../../model/TwistyPlayerModel\";\nimport { globalSafeDocument } from \"../document\";\n\nconst SLOW_DOWN_SCRUBBING = false;\n\nlet isMouseDown = false;\n\nglobalSafeDocument?.addEventListener(\n \"mousedown\",\n function (event) {\n if (event.which) {\n isMouseDown = true;\n }\n },\n true,\n);\n\nglobalSafeDocument?.addEventListener(\n \"mouseup\",\n function (event) {\n if (event.which) {\n isMouseDown = false;\n }\n },\n true,\n);\n\n// var x = 0;\nlet y = 0;\nlet clickNum = 0;\n\nglobalSafeDocument?.addEventListener(\n \"mousedown\",\n () => {\n clickNum++;\n },\n false,\n);\n\nglobalSafeDocument?.addEventListener(\"mousemove\", onMouseUpdate, false);\nglobalSafeDocument?.addEventListener(\"mouseenter\", onMouseUpdate, false);\n\nfunction onMouseUpdate(e: MouseEvent) {\n // x = e.pageX;\n y = e.pageY;\n // console.log(x, y);\n}\n\nconst lastVal = 0;\nlet lastPreval = 0;\nlet scaling: boolean = false;\nlet currentClickNum = 0;\n\n// Values are integers.\nexport class TwistyScrubber extends ManagedCustomElement {\n constructor(public model?: TwistyPlayerModel) {\n super();\n }\n\n async onDetailedTimelineInfo(\n detailedTimelineInfo: DetailedTimelineInfo,\n ): Promise<void> {\n // TODO: is this efficient enough?\n const inputElem = await this.inputElem();\n inputElem.min = detailedTimelineInfo.timeRange.start.toString();\n inputElem.max = detailedTimelineInfo.timeRange.end.toString();\n inputElem.disabled = inputElem.min === inputElem.max;\n inputElem.value = detailedTimelineInfo.timestamp.toString();\n }\n\n async connectedCallback(): Promise<void> {\n this.addCSS(twistyScrubberCSS);\n this.addElement(await this.inputElem());\n }\n\n #inputElem: Promise<HTMLInputElement> | null = null;\n async inputElem(): Promise<HTMLInputElement> {\n // console.log(\"inputElem\", this.#inputElem);\n return (this.#inputElem ??= (async () => {\n const elem = document.createElement(\"input\");\n elem.type = \"range\";\n elem.disabled = true;\n\n // console.log(\"1\");\n this.model?.detailedTimelineInfo.addFreshListener(\n this.onDetailedTimelineInfo.bind(this),\n );\n // console.log(\"3\");\n elem.addEventListener(\"input\", this.onInput.bind(this));\n\n return elem;\n })());\n }\n\n async onInput(e: Event): Promise<void> {\n if (scaling) {\n return; // TODO\n }\n const inputElem = await this.inputElem();\n await this.slowDown(e, inputElem); // TODO\n\n const value = parseInt(inputElem.value);\n // console.log(\"on input\", value);\n this.model?.playingInfo.set({ playing: false });\n this.model?.timestampRequest.set(value);\n }\n\n async slowDown(e: Event, inputElem: HTMLInputElement): Promise<void> {\n if (!SLOW_DOWN_SCRUBBING) {\n return; // TODO\n }\n\n if (isMouseDown) {\n const rect = inputElem.getBoundingClientRect();\n const sliderY = rect.top + rect.height / 2;\n console.log(sliderY, e, y, isMouseDown);\n\n const yDist = Math.abs(sliderY - y);\n let scale = 1;\n if (yDist > 64) {\n scale = Math.max(Math.pow(2, -(yDist - 64) / 64), 1 / 32);\n }\n const preVal = parseInt(inputElem.value);\n console.log(\"cl\", currentClickNum, clickNum, preVal);\n if (currentClickNum === clickNum) {\n const delta = (preVal - lastPreval) * scale;\n console.log(\"delta\", delta, yDist);\n scaling = true;\n let newVal = preVal;\n newVal =\n lastVal +\n delta * scale +\n (preVal - lastVal) *\n Math.min(1, Math.pow(1 / 2, (yDist * yDist) / 64));\n inputElem.value = newVal.toString();\n console.log(scale);\n scaling = false;\n this.contentWrapper.style.opacity = scale.toString();\n } else {\n currentClickNum = clickNum;\n }\n lastPreval = preVal;\n }\n }\n}\n\ncustomElementsShim.define(\"twisty-scrubber\", TwistyScrubber);\n", "import type { PerspectiveCamera } from \"three\";\nimport { THREEJS } from \"../heavy-code-imports/3d\";\nimport type { TwistyPlayerModel } from \"../model/TwistyPlayerModel\";\nimport { Twisty3DPuzzleWrapper } from \"./3D/Twisty3DPuzzleWrapper\";\nimport { setCameraFromOrbitCoordinates } from \"./3D/Twisty3DVantage\";\n\nexport interface TwistyPlayerScreenshot {\n dataURL: string;\n download: (filename?: string) => Promise<void>;\n}\n\n// TODO: cache\nlet cachedCamera: PerspectiveCamera | null = null;\nexport async function screenshot(\n model: TwistyPlayerModel,\n options?: { width: number; height: number },\n): Promise<TwistyPlayerScreenshot> {\n // TODO: improve async caching\n\n const width = options?.width ?? 2048;\n const height = options?.height ?? 2048;\n const aspectRatio = width / height;\n const camera = (cachedCamera ??= await (async () => {\n return new (await THREEJS).PerspectiveCamera(20, aspectRatio, 0.1, 20);\n })());\n\n const scene = new (await THREEJS).Scene();\n\n const twisty3DWrapper = new Twisty3DPuzzleWrapper(\n model,\n { scheduleRender: () => {} },\n await model.puzzleLoader.get(),\n await model.visualizationStrategy.get(),\n );\n\n // TODO: Pass the stickering to the constructor so we don't have to wait..\n await model.twistySceneModel.stickering.get();\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n // TODO: Find a more robust way to do this.\n await model.legacyPosition.get(); // Force the 3D puzzle listeners for the state to fire.\n\n scene.add(await twisty3DWrapper.twisty3DPuzzle());\n\n const orbitCoordinates = await model.twistySceneModel.orbitCoordinates.get();\n await setCameraFromOrbitCoordinates(camera, orbitCoordinates);\n\n const renderer = new (await THREEJS).WebGLRenderer({\n antialias: true,\n alpha: true,\n });\n renderer.setSize(width, height);\n\n renderer.render(scene, camera);\n const dataURL = renderer.domElement.toDataURL();\n\n const defaultFilename = await getDefaultFilename(model);\n\n return {\n dataURL,\n download: async (filename?: string) => {\n downloadURL(dataURL, filename ?? defaultFilename);\n },\n };\n}\n\nexport async function getDefaultFilename(\n model: TwistyPlayerModel,\n): Promise<string> {\n const [puzzleID, algWithIssues] = await Promise.all([\n model.puzzleID.get(),\n model.alg.get(),\n ]);\n return `[${puzzleID}]${\n algWithIssues.alg.experimentalNumUnits() === 0\n ? \"\"\n : \" \" + algWithIssues.alg.toString()\n }`;\n}\n\nexport function downloadURL(\n url: string,\n name: string,\n extension: string = \"png\",\n): void {\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${name}.${extension}`;\n a.click();\n}\n", "import { CSSSource } from \"./ManagedCustomElement\";\n\n// TODO: figure out why `:host(twisty-player):fullscreen { background-color: white }` doesn't work.\nexport const twistyPlayerCSS = new CSSSource(`\n:host {\n width: 384px;\n height: 256px;\n display: grid;\n\n -webkit-user-select: none;\n user-select: none;\n}\n\n.wrapper {\n display: grid;\n overflow: hidden;\n grid-template-rows: 7fr minmax(1.5em, 0.5fr) minmax(2em, 1fr);\n}\n\n.wrapper > * {\n width: inherit;\n height: inherit;\n overflow: hidden;\n}\n\n.wrapper.controls-none {\n grid-template-rows: 7fr;\n}\n\n.wrapper.controls-none twisty-scrubber,\n.wrapper.controls-none twisty-control-button-panel ,\n.wrapper.controls-none twisty-scrubber,\n.wrapper.controls-none twisty-buttons {\n display: none;\n}\n\ntwisty-scrubber {\n background: rgba(196, 196, 196, 0.5);\n}\n\n.wrapper.checkered {\n background-color: #EAEAEA;\n background-image: linear-gradient(45deg, #DDD 25%, transparent 25%, transparent 75%, #DDD 75%, #DDD),\n linear-gradient(45deg, #DDD 25%, transparent 25%, transparent 75%, #DDD 75%, #DDD);\n background-size: 32px 32px;\n background-position: 0 0, 16px 16px;\n}\n\n.visualization-wrapper > * {\n width: 100%;\n height: 100%;\n}\n\n.error-elem {\n width: 100%;\n height: 100%;\n display: none;\n place-content: center;\n font-family: sans-serif;\n box-shadow: inset 0 0 2em rgb(255, 0, 0);\n color: red;\n text-shadow: 0 0 0.2em white;\n background: rgba(255, 255, 255, 0.25);\n}\n\n.wrapper.error .visualization-wrapper {\n display: none;\n}\n\n.wrapper.error .error-elem {\n display: grid;\n}\n`);\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nexport class ArbitraryStringProp extends SimpleTwistyPropSource<string | null> {\n getDefaultValue(): string | null {\n return null;\n }\n}\n", "import { TwistyPropSource } from \"../TwistyProp\";\n\nexport class URLProp extends TwistyPropSource<URL | null, URL | string | null> {\n getDefaultValue(): URL | null {\n return null;\n }\n\n derive(input: URL | string | null): URL | null {\n if (typeof input === \"string\") {\n return new URL(input, location.href); // TODO\n }\n return input;\n }\n}\n", "import { Alg } from \"../../../../../alg\";\nimport { arrayEquals } from \"../../../helpers\";\nimport { TwistyPropSource } from \"../../TwistyProp\";\n\nexport class AlgIssues {\n // TODO: (string | Error)[]\n\n readonly warnings: readonly string[];\n readonly errors: readonly string[];\n\n constructor(issues?: { warnings?: string[]; errors?: string[] }) {\n // TODO: clone inputs?\n this.warnings = Object.freeze(issues?.warnings ?? []);\n this.errors = Object.freeze(issues?.errors ?? []);\n Object.freeze(this);\n }\n\n add(issues?: { warnings?: string[]; errors?: string[] }) {\n return new AlgIssues({\n warnings: this.warnings.concat(issues?.warnings ?? []),\n errors: this.errors.concat(issues?.errors ?? []),\n });\n }\n\n /** @deprecated */\n log() {\n if (this.errors.length > 0) {\n console.error(`\uD83D\uDEA8 ${this.errors[0]}`);\n } else if (this.warnings.length > 0) {\n console.warn(`\u26A0\uFE0F ${this.warnings[0]}`);\n } else {\n console.info(\"\uD83D\uDE0E No issues!\");\n }\n }\n}\n\nexport interface AlgWithIssues {\n alg: Alg;\n issues: AlgIssues;\n}\n\nexport function algWithIssuesFromString(s: string): AlgWithIssues {\n try {\n const alg = Alg.fromString(s); // TODO: is this safe?\n const warnings = [];\n if (alg.toString() !== s) {\n // TODO: Push this check into the parser and return semantic info (so they can be e.g. highlighted).\n warnings.push(`Alg is non-canonical!`);\n }\n return {\n alg,\n issues: new AlgIssues({ warnings }),\n };\n } catch (e) {\n return {\n alg: new Alg(),\n issues: new AlgIssues({\n errors: [`Malformed alg: ${(e as Error).toString()}`],\n }),\n };\n }\n}\n\nfunction algWithIssuesEquals(a1: AlgWithIssues, a2: AlgWithIssues): boolean {\n return (\n a1.alg.isIdentical(a2.alg) &&\n arrayEquals(a1.issues.warnings, a2.issues.warnings) &&\n arrayEquals(a1.issues.errors, a2.issues.errors)\n );\n}\n\nexport class AlgProp extends TwistyPropSource<AlgWithIssues, Alg | string> {\n getDefaultValue(): AlgWithIssues {\n return { alg: new Alg(), issues: new AlgIssues() };\n }\n\n canReuseValue(v1: AlgWithIssues, v2: AlgWithIssues) {\n return algWithIssuesEquals(v1, v2);\n }\n\n async derive(newAlg: Alg | string): Promise<AlgWithIssues> {\n if (typeof newAlg === \"string\") {\n return algWithIssuesFromString(newAlg);\n } else {\n return {\n alg: newAlg,\n issues: new AlgIssues(),\n };\n }\n }\n}\n", "import type { KPuzzle, KTransformation } from \"../../../../../kpuzzle\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { AlgWithIssues } from \"./AlgProp\";\n\ntype AlgTransformationPropInputs = {\n setupAlg: AlgWithIssues;\n kpuzzle: KPuzzle;\n};\n\nexport class AlgTransformationProp extends TwistyPropDerived<\n AlgTransformationPropInputs,\n KTransformation\n> {\n derive(input: AlgTransformationPropInputs): KTransformation {\n return input.kpuzzle.algToTransformation(input.setupAlg.alg);\n }\n}\n", "import type { KTransformation } from \"../../../../../kpuzzle\";\nimport type { AlgIndexer } from \"../../../../controllers/indexer/AlgIndexer\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { SetupToLocation } from \"./SetupAnchorProp\";\n\ninterface AnchorTransformationPropInputs {\n setupTransformation: KTransformation | null;\n setupAnchor: SetupToLocation;\n setupAlgTransformation: KTransformation;\n indexer: AlgIndexer;\n}\n\nexport class AnchorTransformationProp extends TwistyPropDerived<\n AnchorTransformationPropInputs,\n KTransformation\n> {\n derive(inputs: AnchorTransformationPropInputs): KTransformation {\n if (inputs.setupTransformation) {\n return inputs.setupTransformation;\n }\n switch (inputs.setupAnchor) {\n case \"start\":\n return inputs.setupAlgTransformation;\n case \"end\": {\n const algTransformation = inputs.indexer.transformationAtIndex(\n inputs.indexer.numAnimatedLeaves(),\n );\n const inverseAlgTransformation = algTransformation.invert();\n return inputs.setupAlgTransformation.applyTransformation(\n inverseAlgTransformation,\n );\n }\n default:\n throw new Error(\"Unimplemented!\");\n }\n }\n}\n", "import type { Move } from \"../../../../../alg\";\nimport { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport interface CatchUpMove {\n move: Move | null;\n amount: number;\n}\n\nexport class CatchUpMoveProp extends SimpleTwistyPropSource<CatchUpMove> {\n getDefaultValue(): CatchUpMove {\n return { move: null, amount: 0 };\n }\n\n canReuseValue(v1: CatchUpMove, v2: CatchUpMove) {\n return v1.move === v2.move && v1.amount === v2.amount;\n }\n}\n", "import type { Move } from \"../../../../../alg\";\nimport type { CurrentMoveInfo } from \"../../../../controllers/indexer/AlgIndexer\";\nimport { arrayEqualsCompare } from \"../../../helpers\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\n\ninterface CurrentLeavesSimplifiedPropInputs {\n currentMoveInfo: CurrentMoveInfo;\n}\n\nexport interface CurrentLeavesSimplified {\n stateIndex: number;\n movesFinishing: Move[];\n movesFinished: Move[];\n}\n\n// This started as a version of `CurrentLeaves` without highly timestamp-sensitive info like fractions, to enable easier caching.\nexport class CurrentLeavesSimplifiedProp extends TwistyPropDerived<\n CurrentLeavesSimplifiedPropInputs,\n CurrentLeavesSimplified\n> {\n derive(inputs: CurrentLeavesSimplifiedPropInputs): CurrentLeavesSimplified {\n return {\n stateIndex: inputs.currentMoveInfo.stateIndex,\n movesFinishing: inputs.currentMoveInfo.movesFinishing.map(\n (currentMoveInfo) => currentMoveInfo.move,\n ),\n movesFinished: inputs.currentMoveInfo.movesFinished.map(\n (currentMoveInfo) => currentMoveInfo.move,\n ),\n };\n }\n\n canReuse(v1: CurrentLeavesSimplified, v2: CurrentLeavesSimplified): boolean {\n return (\n v1.stateIndex === v2.stateIndex &&\n arrayEqualsCompare(\n v1.movesFinishing,\n v2.movesFinishing,\n (m1: Move, m2: Move) => m1.isIdentical(m2),\n ) &&\n arrayEqualsCompare(\n v1.movesFinished,\n v2.movesFinished,\n (m1: Move, m2: Move) => m1.isIdentical(m2),\n )\n );\n }\n}\n", "import { Move } from \"../../../../../alg\";\nimport { Direction } from \"../../../../controllers/AnimationTypes\";\nimport type {\n AlgIndexer,\n CurrentMoveInfo,\n} from \"../../../../controllers/indexer/AlgIndexer\";\nimport type { DetailedTimelineInfo } from \"../../timeline/DetailedTimelineInfoProp\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { CatchUpMove } from \"./CatchUpMoveProp\";\n\ninterface PositionPropInputs {\n indexer: AlgIndexer;\n detailedTimelineInfo: DetailedTimelineInfo;\n catchUpMove: CatchUpMove;\n}\n\n// TODO: Rename \"current\" (implies a single one) to \"active\"?\nexport class CurrentMoveInfoProp extends TwistyPropDerived<\n PositionPropInputs,\n CurrentMoveInfo\n> {\n derive(inputs: PositionPropInputs): CurrentMoveInfo {\n function addCatchUpMove(currentMoveInfo: CurrentMoveInfo): CurrentMoveInfo {\n if (\n inputs.detailedTimelineInfo.atEnd &&\n inputs.catchUpMove.move !== null\n ) {\n currentMoveInfo.currentMoves.push({\n move: inputs.catchUpMove.move,\n direction: Direction.Backwards,\n fraction: 1 - inputs.catchUpMove.amount,\n startTimestamp: -1, // TODO\n endTimestamp: -1, // TODO\n });\n }\n return currentMoveInfo;\n }\n\n // Copied from AlgCursor\n if (inputs.indexer.currentMoveInfo) {\n return addCatchUpMove(\n inputs.indexer.currentMoveInfo(inputs.detailedTimelineInfo.timestamp),\n );\n } else {\n const idx = inputs.indexer.timestampToIndex(\n inputs.detailedTimelineInfo.timestamp,\n );\n const currentMoveInfo: CurrentMoveInfo = {\n stateIndex: idx,\n currentMoves: [],\n movesFinishing: [],\n movesFinished: [],\n movesStarting: [],\n latestStart: -Infinity,\n earliestEnd: Infinity,\n };\n\n if (inputs.indexer.numAnimatedLeaves() > 0) {\n const move = inputs.indexer.getAnimLeaf(idx)?.as(Move);\n if (!move) {\n return addCatchUpMove(currentMoveInfo);\n }\n const start = inputs.indexer.indexToMoveStartTimestamp(idx);\n const duration = inputs.indexer.moveDuration(idx);\n const fraction =\n (inputs.detailedTimelineInfo.timestamp - start) / duration;\n const end = start + duration;\n const currentMove = {\n move,\n direction: Direction.Forwards,\n fraction,\n startTimestamp: start,\n endTimestamp: end,\n };\n if (fraction === 0) {\n currentMoveInfo.movesStarting.push(currentMove);\n // // TODO: push this into the indexer\n // position.state = combineTransformations(\n // inputs.def,\n // state,\n // transformationForMove(inputs.def, move),\n // ) as Transformation;\n } else if (fraction === 1) {\n currentMoveInfo.movesFinishing.push(currentMove);\n // // TODO: push this into the indexer\n // position.state = combineTransformations(\n // inputs.def,\n // state,\n // transformationForMove(inputs.def, move),\n // ) as Transformation;\n } else {\n // TODO\n currentMoveInfo.currentMoves.push(currentMove);\n currentMoveInfo.latestStart = Math.max(\n currentMoveInfo.latestStart,\n start,\n );\n currentMoveInfo.earliestEnd = Math.min(\n currentMoveInfo.earliestEnd,\n end,\n );\n }\n // }\n // }\n }\n return addCatchUpMove(currentMoveInfo);\n }\n }\n}\n", "import type { KTransformation } from \"../../../../../kpuzzle\";\nimport type { KState } from \"../../../../../kpuzzle/KState\";\nimport type { AlgIndexer } from \"../../../../controllers/indexer/AlgIndexer\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { CurrentLeavesSimplified } from \"./CurrentLeavesSimplified\";\n\ninterface CurrentTransformationPropInputs {\n anchoredStart: KTransformation; // kpuzzle todo: KState?\n currentLeavesSimplified: CurrentLeavesSimplified;\n indexer: AlgIndexer;\n}\n\n// TODO: Make this so we don't have to handle the finishing moves?\nexport class CurrentStateProp extends TwistyPropDerived<\n CurrentTransformationPropInputs,\n KState\n> {\n derive(inputs: CurrentTransformationPropInputs): KState {\n let transformation: KTransformation = inputs.indexer.transformationAtIndex(\n inputs.currentLeavesSimplified.stateIndex,\n );\n transformation = inputs.anchoredStart.applyTransformation(transformation);\n\n // TODO: handle non-commutative finished/finishing/current moves.\n for (const finishingMove of inputs.currentLeavesSimplified.movesFinishing) {\n transformation = transformation.applyMove(finishingMove);\n }\n for (const finishedMove of inputs.currentLeavesSimplified.movesFinished) {\n transformation = transformation.applyMove(finishedMove);\n }\n return transformation.toKState(); // kpuzzle todo\n }\n}\n", "import {\n Alg,\n Grouping,\n LineComment,\n Commutator,\n Conjugate,\n Move,\n Newline,\n Pause,\n TraversalUp,\n} from \"../../../alg\";\nimport type { Duration } from \"../AnimationTypes\";\n\nexport function constantDurationForAmount(_amount: number): Duration {\n return 1000;\n}\n\nexport function defaultDurationForAmount(amount: number): Duration {\n switch (Math.abs(amount)) {\n case 0:\n return 0;\n case 1:\n return 1000;\n case 2:\n return 1500;\n default:\n return 2000;\n }\n}\n// eslint-disable-next-line no-inner-declarations\nexport function ExperimentalScaledDefaultDurationForAmount(\n scale: number,\n amount: number,\n): Duration {\n switch (Math.abs(amount)) {\n case 0:\n return 0;\n case 1:\n return scale * 1000;\n case 2:\n return scale * 1500;\n default:\n return scale * 2000;\n }\n}\n\nexport class AlgDuration extends TraversalUp<Duration> {\n // TODO: Pass durationForAmount as Down type instead?\n constructor(\n public durationForAmount: (\n amount: number,\n ) => Duration = defaultDurationForAmount,\n ) {\n super();\n }\n\n public traverseAlg(alg: Alg): Duration {\n let total = 0;\n for (const unit of alg.units()) {\n total += this.traverseUnit(unit);\n }\n return total;\n }\n\n public traverseGrouping(grouping: Grouping): Duration {\n return grouping.amount * this.traverseAlg(grouping.alg);\n }\n\n public traverseMove(move: Move): Duration {\n return this.durationForAmount(move.amount);\n }\n\n public traverseCommutator(commutator: Commutator): Duration {\n return (\n 2 * (this.traverseAlg(commutator.A) + this.traverseAlg(commutator.B))\n );\n }\n\n public traverseConjugate(conjugate: Conjugate): Duration {\n return 2 * this.traverseAlg(conjugate.A) + this.traverseAlg(conjugate.B);\n }\n\n public traversePause(_pause: Pause): Duration {\n return this.durationForAmount(1);\n }\n\n public traverseNewline(_newline: Newline): Duration {\n return this.durationForAmount(1);\n }\n\n public traverseLineComment(_comment: LineComment): Duration {\n return this.durationForAmount(0);\n }\n}\n", "import { Alg, Move, TraversalUp } from \"../../../alg\";\nimport type { KPuzzle, KTransformation } from \"../../../kpuzzle\";\nimport type { KState } from \"../../../kpuzzle/KState\";\nimport { experimentalCountAnimatedLeaves } from \"../../../notation\";\nimport type { Duration, Timestamp } from \"../AnimationTypes\";\nimport { AlgDuration, defaultDurationForAmount } from \"./AlgDuration\";\nimport type { AlgIndexer } from \"./AlgIndexer\";\n\nexport class SimpleAlgIndexer implements AlgIndexer {\n private moves: Alg;\n // TODO: Allow custom `durationFn`.\n private durationFn: TraversalUp<Duration> = new AlgDuration(\n defaultDurationForAmount,\n );\n\n constructor(private kpuzzle: KPuzzle, alg: Alg) {\n // TODO: Avoid assuming all base moves are block moves.\n this.moves = new Alg(alg.experimentalExpand());\n }\n\n public getAnimLeaf(index: number): Move {\n return Array.from(this.moves.units())[index] as Move; // TODO: perf\n }\n\n public indexToMoveStartTimestamp(index: number): Timestamp {\n const alg = new Alg(Array.from(this.moves.units()).slice(0, index)); // TODO\n return this.durationFn.traverseAlg(alg);\n }\n\n public timestampToIndex(timestamp: Timestamp): number {\n let cumulativeTime = 0;\n let i;\n for (i = 0; i < this.numAnimatedLeaves(); i++) {\n cumulativeTime += this.durationFn.traverseMove(this.getAnimLeaf(i));\n if (cumulativeTime >= timestamp) {\n return i;\n }\n }\n return i;\n }\n\n public stateAtIndex(index: number): KState {\n return this.kpuzzle\n .startState()\n .applyTransformation(this.transformationAtIndex(index));\n }\n\n public transformationAtIndex(index: number): KTransformation {\n let state = this.kpuzzle.identityTransformation();\n for (const move of Array.from(this.moves.units()).slice(0, index)) {\n // TODO\n state = state.applyMove(move as Move);\n }\n return state;\n }\n\n public algDuration(): Duration {\n return this.durationFn.traverseAlg(this.moves);\n }\n\n public numAnimatedLeaves(): number {\n // TODO: Cache internally once performance matters.\n return experimentalCountAnimatedLeaves(this.moves);\n }\n\n public moveDuration(index: number): number {\n return this.durationFn.traverseMove(this.getAnimLeaf(index));\n }\n}\n", "import {\n LineComment,\n Commutator,\n Conjugate,\n Pause,\n TraversalUp,\n Move,\n Alg,\n Grouping,\n Newline,\n} from \"../../../../alg\";\nimport type { MillisecondTimestamp } from \"../../AnimationTypes\";\nimport { defaultDurationForAmount } from \"../AlgDuration\";\n\nexport type AnimatedLeafUnit = Move | Pause;\nexport interface LocalAnimLeavesWithRange {\n animLeafUnit: AnimatedLeafUnit;\n msUntilNext: MillisecondTimestamp;\n duration: MillisecondTimestamp;\n}\n\nexport interface AnimLeafWithRange {\n animLeaf: AnimatedLeafUnit;\n start: MillisecondTimestamp;\n end: MillisecondTimestamp;\n}\n\nconst axisLookup: Record<string, \"x\" | \"y\" | \"z\"> = {\n u: \"y\",\n l: \"x\",\n f: \"z\",\n r: \"x\",\n b: \"z\",\n d: \"y\",\n m: \"x\",\n e: \"y\",\n s: \"z\",\n x: \"x\",\n y: \"y\",\n z: \"z\",\n};\n\nfunction isSameAxis(move1: Move, move2: Move): boolean {\n return (\n axisLookup[move1.family[0].toLowerCase()] ===\n axisLookup[move2.family[0].toLowerCase()]\n );\n}\n\n// TODO: Replace this with an optimized implementation.\n// TODO: Consider `(x U)` and `(U x F)` to be simultaneous.\nexport class LocalSimulMoves extends TraversalUp<LocalAnimLeavesWithRange[]> {\n public traverseAlg(alg: Alg): LocalAnimLeavesWithRange[] {\n const processed: LocalAnimLeavesWithRange[][] = [];\n for (const nestedUnit of alg.units()) {\n processed.push(this.traverseUnit(nestedUnit));\n }\n return Array.prototype.concat(...processed) as LocalAnimLeavesWithRange[];\n }\n\n public traverseGroupingOnce(alg: Alg): LocalAnimLeavesWithRange[] {\n if (alg.experimentalIsEmpty()) {\n return [];\n }\n\n for (const unit of alg.units()) {\n if (!unit.is(Move)) {\n // TODO: define the type statically on the class?\n return this.traverseAlg(alg);\n }\n }\n\n const moves = Array.from(alg.units()) as Move[];\n let maxSimulDur = defaultDurationForAmount(moves[0].amount);\n for (let i = 0; i < moves.length - 1; i++) {\n for (let j = 1; j < moves.length; j++) {\n if (!isSameAxis(moves[i], moves[j])) {\n return this.traverseAlg(alg);\n }\n }\n maxSimulDur = Math.max(\n maxSimulDur,\n defaultDurationForAmount(moves[i].amount),\n );\n }\n\n const localMovesWithRange: LocalAnimLeavesWithRange[] = moves.map(\n (blockMove): LocalAnimLeavesWithRange => {\n return {\n animLeafUnit: blockMove,\n msUntilNext: 0,\n duration: maxSimulDur,\n };\n },\n );\n localMovesWithRange[localMovesWithRange.length - 1].msUntilNext =\n maxSimulDur;\n return localMovesWithRange;\n }\n\n public traverseGrouping(grouping: Grouping): LocalAnimLeavesWithRange[] {\n const processed: LocalAnimLeavesWithRange[][] = [];\n\n const segmentOnce: Alg =\n grouping.amount > 0 ? grouping.alg : grouping.alg.invert();\n for (let i = 0; i < Math.abs(grouping.amount); i++) {\n processed.push(this.traverseGroupingOnce(segmentOnce));\n }\n return Array.prototype.concat(...processed) as LocalAnimLeavesWithRange[];\n }\n\n public traverseMove(move: Move): LocalAnimLeavesWithRange[] {\n const duration = defaultDurationForAmount(move.amount);\n return [\n {\n animLeafUnit: move,\n msUntilNext: duration,\n duration,\n },\n ];\n }\n\n public traverseCommutator(\n commutator: Commutator,\n ): LocalAnimLeavesWithRange[] {\n const processed: LocalAnimLeavesWithRange[][] = [];\n const segmentsOnce: Alg[] = [\n commutator.A,\n commutator.B,\n commutator.A.invert(),\n commutator.B.invert(),\n ];\n for (const segment of segmentsOnce) {\n processed.push(this.traverseGroupingOnce(segment));\n }\n return Array.prototype.concat(...processed) as LocalAnimLeavesWithRange[];\n }\n\n public traverseConjugate(conjugate: Conjugate): LocalAnimLeavesWithRange[] {\n const processed: LocalAnimLeavesWithRange[][] = [];\n const segmentsOnce: Alg[] = [\n conjugate.A,\n conjugate.B,\n conjugate.A.invert(),\n ];\n for (const segment of segmentsOnce) {\n processed.push(this.traverseGroupingOnce(segment));\n }\n return Array.prototype.concat(...processed) as LocalAnimLeavesWithRange[];\n }\n\n public traversePause(pause: Pause): LocalAnimLeavesWithRange[] {\n const duration = defaultDurationForAmount(1);\n return [\n {\n animLeafUnit: pause,\n msUntilNext: duration, // TODO\n duration,\n },\n ];\n }\n\n public traverseNewline(_newline: Newline): LocalAnimLeavesWithRange[] {\n return [];\n }\n\n public traverseLineComment(\n _comment: LineComment,\n ): LocalAnimLeavesWithRange[] {\n return [];\n }\n}\n\nconst localSimulMovesInstance = new LocalSimulMoves();\n\nconst localSimulMoves = localSimulMovesInstance.traverseAlg.bind(\n localSimulMovesInstance,\n) as (a: Alg) => LocalAnimLeavesWithRange[];\n\nexport function simulMoves(a: Alg): AnimLeafWithRange[] {\n let timestamp = 0;\n const l = localSimulMoves(a).map(\n (localSimulMove: LocalAnimLeavesWithRange): AnimLeafWithRange => {\n const leafWithRange = {\n animLeaf: localSimulMove.animLeafUnit,\n start: timestamp,\n end: timestamp + localSimulMove.duration,\n };\n timestamp += localSimulMove.msUntilNext;\n return leafWithRange;\n },\n );\n return l;\n}\n", "import { Alg, Move } from \"../../../../alg\";\nimport type { KPuzzle, KTransformation } from \"../../../../kpuzzle\";\nimport type { KState } from \"../../../../kpuzzle/KState\";\nimport {\n Direction,\n Duration,\n PuzzlePosition,\n Timestamp,\n} from \"../../AnimationTypes\";\nimport type { CurrentMove, CurrentMoveInfo } from \"../AlgIndexer\";\nimport { AnimatedLeafUnit, AnimLeafWithRange, simulMoves } from \"./simul-moves\";\n\nconst demos: Record<string, AnimLeafWithRange[]> = {\n \"y' y' U' E D R2 r2 F2 B2 U E D' R2 L2' z2 S2 U U D D S2 F2' B2\": [\n { animLeaf: new Move(\"y\", -1), start: 0, end: 1000 },\n { animLeaf: new Move(\"y\", -1), start: 1000, end: 2000 },\n { animLeaf: new Move(\"U\", -1), start: 1000, end: 1600 },\n { animLeaf: new Move(\"E\", 1), start: 1200, end: 1800 },\n { animLeaf: new Move(\"D\"), start: 1400, end: 2000 },\n { animLeaf: new Move(\"R\", 2), start: 2000, end: 3500 },\n { animLeaf: new Move(\"r\", 2), start: 2000, end: 3500 },\n { animLeaf: new Move(\"F\", 2), start: 3500, end: 4200 },\n { animLeaf: new Move(\"B\", 2), start: 3800, end: 4500 },\n { animLeaf: new Move(\"U\", 1), start: 4500, end: 5500 },\n { animLeaf: new Move(\"E\", 1), start: 4500, end: 5500 },\n { animLeaf: new Move(\"D\", -1), start: 4500, end: 5500 },\n { animLeaf: new Move(\"R\", 2), start: 5500, end: 6500 },\n { animLeaf: new Move(\"L\", -2), start: 5500, end: 6500 },\n { animLeaf: new Move(\"z\", 2), start: 5500, end: 6500 },\n { animLeaf: new Move(\"S\", 2), start: 6500, end: 7500 },\n { animLeaf: new Move(\"U\"), start: 7500, end: 8000 },\n { animLeaf: new Move(\"D\"), start: 7750, end: 8250 },\n { animLeaf: new Move(\"U\"), start: 8000, end: 8500 },\n { animLeaf: new Move(\"D\"), start: 8250, end: 8750 },\n { animLeaf: new Move(\"S\", 2), start: 8750, end: 9250 },\n { animLeaf: new Move(\"F\", -2), start: 8750, end: 10000 },\n { animLeaf: new Move(\"B\", 2), start: 8750, end: 10000 },\n ],\n \"M' R' U' D' M R\": [\n { animLeaf: new Move(\"M\", -1), start: 0, end: 1000 },\n { animLeaf: new Move(\"R\", -1), start: 0, end: 1000 },\n { animLeaf: new Move(\"U\", -1), start: 1000, end: 2000 },\n { animLeaf: new Move(\"D\", -1), start: 1000, end: 2000 },\n { animLeaf: new Move(\"M\"), start: 2000, end: 3000 },\n { animLeaf: new Move(\"R\"), start: 2000, end: 3000 },\n ],\n \"U' E' r E r2' E r U E\": [\n { animLeaf: new Move(\"U\", -1), start: 0, end: 1000 },\n { animLeaf: new Move(\"E\", -1), start: 0, end: 1000 },\n { animLeaf: new Move(\"r\"), start: 1000, end: 2500 },\n { animLeaf: new Move(\"E\"), start: 2500, end: 3500 },\n { animLeaf: new Move(\"r\", -2), start: 3500, end: 5000 },\n { animLeaf: new Move(\"E\"), start: 5000, end: 6000 },\n { animLeaf: new Move(\"r\"), start: 6000, end: 7000 },\n { animLeaf: new Move(\"U\"), start: 7000, end: 8000 },\n { animLeaf: new Move(\"E\"), start: 7000, end: 8000 },\n ],\n};\n\nexport class SimultaneousMoveIndexer {\n private animLeaves: AnimLeafWithRange[];\n // TODO: Allow custom `durationFn`.\n\n constructor(private kpuzzle: KPuzzle, alg: Alg) {\n this.animLeaves = demos[alg.toString()] ?? simulMoves(alg);\n // TODO: Avoid assuming all base moves are block moves.\n }\n\n public getAnimLeaf(index: number): AnimatedLeafUnit | null {\n return (\n this.animLeaves[Math.min(index, this.animLeaves.length - 1)]?.animLeaf ??\n null\n );\n }\n\n private getAnimLeafWithRange(index: number): AnimLeafWithRange {\n return this.animLeaves[Math.min(index, this.animLeaves.length - 1)];\n }\n\n public indexToMoveStartTimestamp(index: number): Timestamp {\n let start = 0;\n if (this.animLeaves.length > 0) {\n start =\n this.animLeaves[Math.min(index, this.animLeaves.length - 1)].start;\n }\n return start;\n }\n\n public timestampToIndex(timestamp: Timestamp): number {\n let i = 0;\n for (i = 0; i < this.animLeaves.length; i++) {\n if (this.animLeaves[i].start >= timestamp) {\n return Math.max(0, i - 1);\n }\n }\n return Math.max(0, i - 1);\n }\n\n public timestampToPosition(\n timestamp: Timestamp,\n startState?: KState,\n ): PuzzlePosition {\n const currentMoveInfo = this.currentMoveInfo(timestamp);\n\n let state = startState ?? this.kpuzzle.identityTransformation().toKState();\n for (const leafWithRange of this.animLeaves.slice(\n 0,\n currentMoveInfo.stateIndex,\n )) {\n const move = leafWithRange.animLeaf.as(Move);\n if (move !== null) {\n state = state.applyMove(move);\n }\n }\n\n return {\n state,\n movesInProgress: currentMoveInfo.currentMoves,\n };\n }\n\n // TODO: Caching\n public currentMoveInfo(timestamp: Timestamp): CurrentMoveInfo {\n // The starting timestamp of the earliest active move.\n let windowEarliestTimestamp = Infinity;\n for (const leafWithRange of this.animLeaves) {\n if (leafWithRange.start <= timestamp && leafWithRange.end >= timestamp) {\n windowEarliestTimestamp = Math.min(\n windowEarliestTimestamp,\n leafWithRange.start,\n );\n } else if (leafWithRange.start > timestamp) {\n break;\n }\n }\n\n const currentMoves: CurrentMove[] = [];\n const movesStarting: CurrentMove[] = [];\n const movesFinishing: CurrentMove[] = [];\n const movesFinished: CurrentMove[] = [];\n let latestStart: number = -Infinity; // TODO: is there a better way to accumulate this?\n let earliestEnd: number = Infinity; // TODO: is there a better way to accumulate this?\n\n let stateIndex: number = 0;\n for (const leafWithRange of this.animLeaves) {\n if (leafWithRange.end <= windowEarliestTimestamp) {\n stateIndex++;\n } else if (leafWithRange.start > timestamp) {\n break;\n } else {\n const move = leafWithRange.animLeaf.as(Move);\n if (move !== null) {\n let fraction =\n (timestamp - leafWithRange.start) /\n (leafWithRange.end - leafWithRange.start);\n let moveFinished = false;\n if (fraction > 1) {\n fraction = 1;\n moveFinished = true;\n }\n const currentMove = {\n move: move,\n direction: Direction.Forwards,\n fraction: fraction,\n startTimestamp: leafWithRange.start,\n endTimestamp: leafWithRange.end,\n };\n switch (fraction) {\n case 0:\n movesStarting.push(currentMove);\n break;\n case 1:\n // Generalize this to avoid reordering commuting moves.\n if (moveFinished) {\n movesFinished.push(currentMove);\n } else {\n movesFinishing.push(currentMove);\n }\n break;\n default:\n currentMoves.push(currentMove);\n latestStart = Math.max(latestStart, leafWithRange.start);\n earliestEnd = Math.min(earliestEnd, leafWithRange.end);\n }\n }\n }\n }\n return {\n stateIndex,\n currentMoves,\n latestStart,\n earliestEnd,\n movesStarting,\n movesFinishing,\n movesFinished,\n };\n }\n\n public stateAtIndex(index: number, startState?: KState): KState {\n let state = startState ?? this.kpuzzle.startState();\n for (let i = 0; i < this.animLeaves.length && i < index; i++) {\n const leafWithRange = this.animLeaves[i];\n const move = leafWithRange.animLeaf.as(Move);\n if (move !== null) {\n state = state.applyMove(move);\n }\n }\n return state;\n }\n\n public transformationAtIndex(index: number): KTransformation {\n let transformation = this.kpuzzle.identityTransformation();\n for (const leafWithRange of this.animLeaves.slice(0, index)) {\n const move = leafWithRange.animLeaf.as(Move);\n if (move !== null) {\n transformation = transformation.applyMove(move);\n }\n }\n return transformation;\n }\n\n public algDuration(): Duration {\n let max = 0;\n for (const leafWithRange of this.animLeaves) {\n max = Math.max(max, leafWithRange.end);\n }\n return max;\n }\n\n public numAnimatedLeaves(): number {\n // TODO: Cache internally once performance matters.\n return this.animLeaves.length;\n }\n\n public moveDuration(index: number): number {\n const move = this.getAnimLeafWithRange(index);\n return move.end - move.start;\n }\n}\n", "import {\n Alg,\n Commutator,\n Conjugate,\n experimentalDirectedGenerator,\n ExperimentalIterationDirection,\n Grouping,\n LineComment,\n Move,\n Newline,\n Pause,\n TraversalDownUp,\n TraversalUp,\n Unit,\n} from \"../../../../alg\";\nimport type { KPuzzle, KTransformation } from \"../../../../kpuzzle\";\nimport type { Duration } from \"../../AnimationTypes\";\nimport { AlgDuration, defaultDurationForAmount } from \"../AlgDuration\";\n\nexport class AlgPartDecoration {\n constructor(\n public moveCount: number,\n public duration: number,\n public forward: KTransformation,\n public backward: KTransformation,\n public children: Array<AlgPartDecoration> = [],\n ) {}\n}\nexport class DecoratorConstructor extends TraversalUp<AlgPartDecoration> {\n private identity: KTransformation;\n private dummyLeaf: AlgPartDecoration;\n private durationFn: TraversalUp<Duration> = new AlgDuration(\n defaultDurationForAmount,\n );\n\n private cache: { [key: string]: AlgPartDecoration } = {};\n\n constructor(private kpuzzle: KPuzzle) {\n super();\n this.identity = kpuzzle.identityTransformation();\n this.dummyLeaf = new AlgPartDecoration(\n 0,\n 0,\n this.identity,\n this.identity,\n [],\n );\n }\n\n public traverseAlg(alg: Alg): AlgPartDecoration {\n let moveCount = 0;\n let duration = 0;\n let transformation = this.identity;\n const child: Array<AlgPartDecoration> = [];\n for (const unit of alg.units()) {\n const apd = this.traverseUnit(unit);\n moveCount += apd.moveCount;\n duration += apd.duration;\n if (transformation === this.identity) {\n transformation = apd.forward;\n } else {\n transformation = transformation.applyTransformation(apd.forward);\n }\n child.push(apd);\n }\n return new AlgPartDecoration(\n moveCount,\n duration,\n transformation,\n transformation.invert(),\n child,\n );\n }\n\n public traverseGrouping(grouping: Grouping): AlgPartDecoration {\n const dec = this.traverseAlg(grouping.alg);\n return this.mult(dec, grouping.amount, [dec]);\n }\n\n public traverseMove(move: Move): AlgPartDecoration {\n const key = move.toString();\n let r: AlgPartDecoration | undefined = this.cache[key];\n if (r) {\n return r;\n }\n const transformation = this.kpuzzle.moveToTransformation(move);\n r = new AlgPartDecoration(\n 1,\n this.durationFn.traverseUnit(move),\n transformation,\n transformation.invert(),\n );\n this.cache[key] = r;\n return r;\n }\n\n public traverseCommutator(commutator: Commutator): AlgPartDecoration {\n const decA = this.traverseAlg(commutator.A);\n const decB = this.traverseAlg(commutator.B);\n const AB = decA.forward.applyTransformation(decB.forward);\n const ApBp = decA.backward.applyTransformation(decB.backward);\n const ABApBp = AB.applyTransformation(ApBp);\n const dec = new AlgPartDecoration(\n 2 * (decA.moveCount + decB.moveCount),\n 2 * (decA.duration + decB.duration),\n ABApBp,\n ABApBp.invert(),\n [decA, decB],\n );\n return this.mult(dec, 1, [dec, decA, decB]);\n }\n\n public traverseConjugate(conjugate: Conjugate): AlgPartDecoration {\n const decA = this.traverseAlg(conjugate.A);\n const decB = this.traverseAlg(conjugate.B);\n const AB = decA.forward.applyTransformation(decB.forward);\n const ABAp = AB.applyTransformation(decA.backward);\n const dec = new AlgPartDecoration(\n 2 * decA.moveCount + decB.moveCount,\n 2 * decA.duration + decB.duration,\n ABAp,\n ABAp.invert(),\n [decA, decB],\n );\n return this.mult(dec, 1, [dec, decA, decB]);\n }\n\n public traversePause(pause: Pause): AlgPartDecoration {\n return new AlgPartDecoration(\n 1,\n this.durationFn.traverseUnit(pause),\n this.identity,\n this.identity,\n );\n }\n\n public traverseNewline(_newline: Newline): AlgPartDecoration {\n return this.dummyLeaf;\n }\n\n public traverseLineComment(_comment: LineComment): AlgPartDecoration {\n return this.dummyLeaf;\n }\n\n private mult(\n apd: AlgPartDecoration,\n n: number,\n child: Array<AlgPartDecoration>,\n ): AlgPartDecoration {\n const absn = Math.abs(n);\n const st = apd.forward.selfMultiply(n);\n return new AlgPartDecoration(\n apd.moveCount * absn,\n apd.duration * absn,\n st,\n st.invert(),\n child,\n );\n }\n}\nclass WalkerDown {\n constructor(public apd: AlgPartDecoration, public back: boolean) {\n /**/\n }\n}\nexport class AlgWalker extends TraversalDownUp<WalkerDown, boolean> {\n public move?: Unit;\n public moveDuration: number;\n public back: boolean;\n public st: KTransformation;\n public root: WalkerDown;\n public i: number;\n public dur: number;\n private goali: number;\n private goaldur: number;\n constructor(\n public kpuzzle: KPuzzle,\n public algOrUnit: Alg | Unit, // TODO: can we keep these separate?\n public apd: AlgPartDecoration,\n ) {\n super();\n this.i = -1;\n this.dur = -1;\n this.goali = -1;\n this.goaldur = -1;\n this.move = undefined;\n this.back = false;\n this.moveDuration = 0;\n this.st = this.kpuzzle.identityTransformation();\n this.root = new WalkerDown(this.apd, false);\n }\n\n public moveByIndex(loc: number): boolean {\n if (this.i >= 0 && this.i === loc) {\n return this.move !== undefined;\n }\n return this.dosearch(loc, Infinity);\n }\n\n public moveByDuration(dur: number): boolean {\n if (\n this.dur >= 0 &&\n this.dur < dur &&\n this.dur + this.moveDuration >= dur\n ) {\n return this.move !== undefined;\n }\n return this.dosearch(Infinity, dur);\n }\n\n public dosearch(loc: number, dur: number): boolean {\n this.goali = loc;\n this.goaldur = dur;\n this.i = 0;\n this.dur = 0;\n this.move = undefined;\n this.moveDuration = 0;\n this.back = false;\n this.st = this.kpuzzle.identityTransformation();\n const r = this.algOrUnit.is(Alg)\n ? this.traverseAlg(this.algOrUnit as Alg, this.root)\n : this.traverseUnit(this.algOrUnit as Unit, this.root); // TODO\n return r;\n }\n\n public traverseAlg(alg: Alg, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n let i = wd.back ? alg.experimentalNumUnits() - 1 : 0;\n for (const unit of experimentalDirectedGenerator(\n alg.units(),\n wd.back\n ? ExperimentalIterationDirection.Backwards\n : ExperimentalIterationDirection.Forwards,\n )) {\n if (\n this.traverseUnit(unit, new WalkerDown(wd.apd.children[i], wd.back))\n ) {\n return true;\n }\n i += wd.back ? -1 : 1;\n }\n return false;\n }\n\n public traverseGrouping(grouping: Grouping, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n const back = this.domult(wd, grouping.amount);\n return this.traverseAlg(\n grouping.alg,\n new WalkerDown(wd.apd.children[0], back),\n );\n }\n\n public traverseMove(move: Move, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n this.move = move;\n this.moveDuration = wd.apd.duration;\n this.back = wd.back;\n return true;\n }\n\n public traverseCommutator(commutator: Commutator, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n const back = this.domult(wd, 1);\n if (back) {\n return (\n this.traverseAlg(\n commutator.B,\n new WalkerDown(wd.apd.children[2], !back),\n ) ||\n this.traverseAlg(\n commutator.A,\n new WalkerDown(wd.apd.children[1], !back),\n ) ||\n this.traverseAlg(\n commutator.B,\n new WalkerDown(wd.apd.children[2], back),\n ) ||\n this.traverseAlg(commutator.A, new WalkerDown(wd.apd.children[1], back))\n );\n } else {\n return (\n this.traverseAlg(\n commutator.A,\n new WalkerDown(wd.apd.children[1], back),\n ) ||\n this.traverseAlg(\n commutator.B,\n new WalkerDown(wd.apd.children[2], back),\n ) ||\n this.traverseAlg(\n commutator.A,\n new WalkerDown(wd.apd.children[1], !back),\n ) ||\n this.traverseAlg(\n commutator.B,\n new WalkerDown(wd.apd.children[2], !back),\n )\n );\n }\n }\n\n public traverseConjugate(conjugate: Conjugate, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n const back = this.domult(wd, 1);\n if (back) {\n return (\n this.traverseAlg(\n conjugate.A,\n new WalkerDown(wd.apd.children[1], !back),\n ) ||\n this.traverseAlg(\n conjugate.B,\n new WalkerDown(wd.apd.children[2], back),\n ) ||\n this.traverseAlg(conjugate.A, new WalkerDown(wd.apd.children[1], back))\n );\n } else {\n return (\n this.traverseAlg(\n conjugate.A,\n new WalkerDown(wd.apd.children[1], back),\n ) ||\n this.traverseAlg(\n conjugate.B,\n new WalkerDown(wd.apd.children[2], back),\n ) ||\n this.traverseAlg(conjugate.A, new WalkerDown(wd.apd.children[1], !back))\n );\n }\n }\n\n public traversePause(pause: Pause, wd: WalkerDown): boolean {\n if (!this.firstcheck(wd)) {\n return false;\n }\n this.move = pause;\n this.moveDuration = wd.apd.duration;\n this.back = wd.back;\n return true;\n }\n\n public traverseNewline(_newline: Newline, _wd: WalkerDown): boolean {\n return false;\n }\n\n public traverseLineComment(\n _lineComment: LineComment,\n _wd: WalkerDown,\n ): boolean {\n return false;\n }\n\n private firstcheck(wd: WalkerDown): boolean {\n if (\n wd.apd.moveCount + this.i <= this.goali &&\n wd.apd.duration + this.dur < this.goaldur\n ) {\n return this.keepgoing(wd);\n }\n return true;\n }\n\n private domult(wd: WalkerDown, amount: number): boolean {\n let back = wd.back;\n if (amount === 0) {\n // I don't believe this will ever happen\n return back;\n }\n if (amount < 0) {\n back = !back;\n amount = -amount;\n }\n const base = wd.apd.children[0];\n const full = Math.min(\n Math.floor((this.goali - this.i) / base.moveCount),\n Math.ceil((this.goaldur - this.dur) / base.duration - 1),\n );\n if (full > 0) {\n this.keepgoing(new WalkerDown(base, back), full);\n }\n return back;\n }\n\n private keepgoing(wd: WalkerDown, mul: number = 1): boolean {\n this.i += mul * wd.apd.moveCount;\n this.dur += mul * wd.apd.duration;\n if (mul !== 1) {\n if (wd.back) {\n this.st = this.st.applyTransformation(\n wd.apd.backward.selfMultiply(mul),\n );\n } else {\n this.st = this.st.applyTransformation(wd.apd.forward.selfMultiply(mul));\n }\n } else {\n if (wd.back) {\n this.st = this.st.applyTransformation(wd.apd.backward);\n } else {\n this.st = this.st.applyTransformation(wd.apd.forward);\n }\n }\n return false;\n }\n}\n", "import {\n Alg,\n Commutator,\n Conjugate,\n Grouping,\n LineComment,\n Move,\n Newline,\n Pause,\n TraversalUp,\n Unit,\n} from \"../../../../alg\";\nimport { AlgBuilder } from \"../../../../alg\";\n\nconst MIN_CHUNKING_THRESHOLD = 16;\n\nfunction chunkifyAlg(alg: Alg, chunkMaxLength: number): Alg {\n const mainAlgBuilder = new AlgBuilder();\n const chunkAlgBuilder = new AlgBuilder();\n for (const unit of alg.units()) {\n chunkAlgBuilder.push(unit);\n if (chunkAlgBuilder.experimentalNumUnits() >= chunkMaxLength) {\n mainAlgBuilder.push(new Grouping(chunkAlgBuilder.toAlg()));\n chunkAlgBuilder.reset();\n }\n }\n mainAlgBuilder.push(new Grouping(chunkAlgBuilder.toAlg()));\n return mainAlgBuilder.toAlg();\n}\n\nclass ChunkAlgs extends TraversalUp<Alg, Unit> {\n traverseAlg(alg: Alg): Alg {\n const algLength = alg.experimentalNumUnits();\n if (algLength < MIN_CHUNKING_THRESHOLD) {\n return alg;\n }\n return chunkifyAlg(alg, Math.ceil(Math.sqrt(algLength)));\n }\n\n traverseGrouping(grouping: Grouping): Unit {\n return new Grouping(\n this.traverseAlg(grouping.alg),\n grouping.amount, // TODO\n );\n }\n\n traverseMove(move: Move): Unit {\n return move;\n }\n\n traverseCommutator(commutator: Commutator): Unit {\n return new Conjugate(\n this.traverseAlg(commutator.A),\n this.traverseAlg(commutator.B),\n );\n }\n\n traverseConjugate(conjugate: Conjugate): Unit {\n return new Conjugate(\n this.traverseAlg(conjugate.A),\n this.traverseAlg(conjugate.B),\n );\n }\n\n traversePause(pause: Pause): Unit {\n return pause;\n }\n\n traverseNewline(newline: Newline): Unit {\n return newline;\n }\n\n traverseLineComment(comment: LineComment): Unit {\n return comment;\n }\n}\n\nconst chunkAlgsInstance = new ChunkAlgs();\nexport const chunkAlgs = chunkAlgsInstance.traverseAlg.bind(\n chunkAlgsInstance,\n) as (alg: Alg) => Alg;\n", "import type { Alg, Move } from \"../../../../alg\";\nimport type { KPuzzle, KTransformation } from \"../../../../kpuzzle\";\nimport type { KState } from \"../../../../kpuzzle/KState\";\nimport type { Duration, Timestamp } from \"../../AnimationTypes\";\nimport type { AlgIndexer } from \"../AlgIndexer\";\nimport {\n AlgPartDecoration,\n AlgWalker,\n DecoratorConstructor,\n} from \"./AlgWalker\";\nimport { chunkAlgs } from \"./chunkAlgs\";\n\nexport class TreeAlgIndexer implements AlgIndexer {\n private decoration: AlgPartDecoration;\n private walker: AlgWalker;\n constructor(private kpuzzle: KPuzzle, alg: Alg) {\n const deccon = new DecoratorConstructor(this.kpuzzle);\n\n const chunkedAlg = chunkAlgs(alg);\n\n this.decoration = deccon.traverseAlg(chunkedAlg);\n this.walker = new AlgWalker(this.kpuzzle, chunkedAlg, this.decoration);\n }\n\n public getAnimLeaf(index: number): Move | null {\n // FIXME need to support Pause\n if (this.walker.moveByIndex(index)) {\n if (!this.walker.move) {\n throw new Error(\"`this.walker.mv` missing\");\n }\n const move = this.walker.move as Move;\n // TODO: this type of negation needs to be in alg\n if (this.walker.back) {\n return move.invert();\n }\n return move;\n }\n return null;\n }\n\n public indexToMoveStartTimestamp(index: number): Timestamp {\n if (this.walker.moveByIndex(index) || this.walker.i === index) {\n return this.walker.dur;\n }\n throw new Error(`Out of algorithm: index ${index}`);\n }\n\n public indexToMovesInProgress(index: number): Timestamp {\n if (this.walker.moveByIndex(index) || this.walker.i === index) {\n return this.walker.dur;\n }\n throw new Error(`Out of algorithm: index ${index}`);\n }\n\n public stateAtIndex(index: number, startState?: KState): KState {\n this.walker.moveByIndex(index);\n return (startState ?? this.kpuzzle.startState()).applyTransformation(\n this.walker.st,\n );\n }\n\n // TransformAtIndex does not reflect the start state; it only reflects\n // the change from the start state to the current move index. If you\n // want the actual state, use stateAtIndex.\n public transformationAtIndex(index: number): KTransformation {\n this.walker.moveByIndex(index);\n return this.walker.st;\n }\n\n public numAnimatedLeaves(): number {\n return this.decoration.moveCount;\n }\n\n public timestampToIndex(timestamp: Timestamp): number {\n this.walker.moveByDuration(timestamp);\n return this.walker.i;\n }\n\n public algDuration(): Duration {\n return this.decoration.duration;\n }\n\n public moveDuration(index: number): number {\n this.walker.moveByIndex(index);\n return this.walker.moveDuration;\n }\n}\n", "import type { AlgIndexer } from \"../../../..\";\nimport type { Alg } from \"../../../../../alg\";\nimport type { KPuzzle } from \"../../../../../kpuzzle\";\nimport { experimentalCountMoves } from \"../../../../../notation\";\nimport { SimpleAlgIndexer } from \"../../../../controllers/indexer/SimpleAlgIndexer\";\nimport { SimultaneousMoveIndexer } from \"../../../../controllers/indexer/simultaneous-moves/SimultaneousMoveIndexer\";\nimport { TreeAlgIndexer } from \"../../../../controllers/indexer/tree/TreeAlgIndexer\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { VisualizationStrategy } from \"../../viewer/VisualizationStrategyProp\";\nimport type { PuzzleID } from \"../structure/PuzzleIDRequestProp\";\nimport type { AlgWithIssues } from \"./AlgProp\";\nimport type { IndexerStrategyName } from \"./IndexerConstructorRequestProp\";\n\nexport type IndexerConstructor = new (kpuzzle: KPuzzle, alg: Alg) => AlgIndexer;\n\ninterface IndexerConstructorPropInputs {\n puzzle: PuzzleID;\n alg: AlgWithIssues;\n visualizationStrategy: VisualizationStrategy;\n indexerConstructorRequest: IndexerStrategyName;\n}\n\n// TODO: Also handle PG3D vs. 3D\nexport class IndexerConstructorProp extends TwistyPropDerived<\n IndexerConstructorPropInputs,\n IndexerConstructor\n> {\n derive(inputs: IndexerConstructorPropInputs): IndexerConstructor {\n switch (inputs.indexerConstructorRequest) {\n case \"auto\":\n if (\n experimentalCountMoves(inputs.alg.alg) < 100 &&\n inputs.puzzle === \"3x3x3\" &&\n inputs.visualizationStrategy === \"Cube3D\"\n ) {\n return SimultaneousMoveIndexer;\n } else {\n return TreeAlgIndexer;\n }\n case \"tree\":\n return TreeAlgIndexer;\n case \"simple\":\n return SimpleAlgIndexer;\n case \"simultaneous\":\n return SimultaneousMoveIndexer;\n default:\n throw new Error(\"Invalid indexer request!\");\n }\n }\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport const indexerStrategyNames = {\n auto: true,\n simple: true,\n tree: true,\n simultaneous: true,\n};\nexport type IndexerStrategyName = keyof typeof indexerStrategyNames;\n\nexport class IndexerConstructorRequestProp extends SimpleTwistyPropSource<IndexerStrategyName> {\n getDefaultValue(): IndexerStrategyName {\n return \"auto\";\n }\n}\n", "import type { KPuzzle } from \"../../../../../kpuzzle\";\nimport type { AlgIndexer } from \"../../../../controllers/indexer/AlgIndexer\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { AlgWithIssues } from \"./AlgProp\";\nimport type { IndexerConstructor } from \"./IndexerConstructorProp\";\n\ntype IndexerPropInputs = {\n indexerConstructor: IndexerConstructor;\n algWithIssues: AlgWithIssues;\n kpuzzle: KPuzzle;\n};\nexport class IndexerProp extends TwistyPropDerived<\n IndexerPropInputs,\n AlgIndexer\n> {\n derive(input: IndexerPropInputs): AlgIndexer {\n return new input.indexerConstructor(input.kpuzzle, input.algWithIssues.alg);\n }\n}\n", "import type { KState } from \"../../../../../kpuzzle/KState\";\nimport type { PuzzlePosition } from \"../../../../controllers/AnimationTypes\";\nimport type { CurrentMoveInfo } from \"../../../../controllers/indexer/AlgIndexer\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\n\nexport interface LegacyPositionPropInputs {\n currentMoveInfo: CurrentMoveInfo;\n state: KState;\n}\n\n// TODO: This exist as a convenience for old `Twisty3D` implementations. Get rid of this.\nexport class LegacyPositionProp extends TwistyPropDerived<\n LegacyPositionPropInputs,\n PuzzlePosition\n> {\n derive(inputs: LegacyPositionPropInputs): PuzzlePosition {\n return {\n state: inputs.state,\n movesInProgress: inputs.currentMoveInfo.currentMoves,\n };\n }\n}\n", "import { experimentalCountMoves } from \"../../../../../notation\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { AlgWithIssues } from \"./AlgProp\";\n\ninterface NaiveMoveCountPropInputs {\n alg: AlgWithIssues;\n}\n\n// TODO: handle metrics\nexport class NaiveMoveCountProp extends TwistyPropDerived<\n NaiveMoveCountPropInputs,\n number | null\n> {\n derive(inputs: NaiveMoveCountPropInputs): number | null {\n if (inputs.alg.issues.errors.length > 0) {\n return null;\n }\n return experimentalCountMoves(inputs.alg.alg);\n }\n}\n", "import { Alg } from \"../../../../../alg\";\nimport type { KPuzzle } from \"../../../../../kpuzzle\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport { AlgIssues, AlgWithIssues } from \"./AlgProp\";\n\nlet validate: boolean = true;\nexport function experimentalSetPuzzleAlgValidation(newValidate: boolean): void {\n validate = newValidate;\n}\n\nexport class PuzzleAlgProp extends TwistyPropDerived<\n { algWithIssues: AlgWithIssues; kpuzzle: KPuzzle },\n AlgWithIssues\n> {\n async derive(inputs: {\n algWithIssues: AlgWithIssues;\n kpuzzle: KPuzzle;\n }): Promise<AlgWithIssues> {\n try {\n if (validate) {\n inputs.kpuzzle.algToTransformation(inputs.algWithIssues.alg);\n }\n\n // Looks like we could apply the alg!\n return inputs.algWithIssues;\n } catch (e) {\n return {\n alg: new Alg(),\n issues: new AlgIssues({\n errors: [`Invalid alg for puzzle: ${(e as Error).toString()}`],\n }),\n };\n }\n }\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\n// TODO: turn these maps into lists?\nexport const setupToLocations = {\n start: true, // default // TODO: \"beginning\"\n end: true,\n};\nexport type SetupToLocation = keyof typeof setupToLocations;\n\nexport class SetupAnchorProp extends SimpleTwistyPropSource<SetupToLocation> {\n getDefaultValue(): SetupToLocation {\n return \"start\";\n }\n}\n", "import type { KTransformation } from \"../../../../../kpuzzle\";\nimport { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport class SetupTransformationProp extends SimpleTwistyPropSource<KTransformation | null> {\n getDefaultValue(): KTransformation | null {\n return null;\n }\n}\n", "import type { KPuzzle } from \"../../../../../kpuzzle\";\nimport type { PuzzleLoader } from \"../../../../../puzzles\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\n\nexport class KPuzzleProp extends TwistyPropDerived<\n { puzzleLoader: PuzzleLoader },\n KPuzzle\n> {\n async derive(inputs: { puzzleLoader: PuzzleLoader }): Promise<KPuzzle> {\n return inputs.puzzleLoader.kpuzzle();\n }\n}\n", "import type { PuzzleDescriptionString } from \"../../../../../puzzle-geometry/PGPuzzles\";\nimport {\n NoValueType,\n NO_VALUE,\n SimpleTwistyPropSource,\n} from \"../../TwistyProp\";\n\nexport class PGPuzzleDescriptionStringProp extends SimpleTwistyPropSource<\n PuzzleDescriptionString | NoValueType\n> {\n getDefaultValue(): PuzzleDescriptionString | NoValueType {\n return NO_VALUE;\n }\n}\n", "import type { PuzzleLoader } from \"../../../../../puzzles\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\nimport type { PuzzleID } from \"./PuzzleIDRequestProp\";\n\nexport class PuzzleIDProp extends TwistyPropDerived<\n { puzzleLoader: PuzzleLoader },\n PuzzleID\n> {\n async derive(inputs: { puzzleLoader: PuzzleLoader }): Promise<PuzzleID> {\n return inputs.puzzleLoader.id as PuzzleID;\n }\n}\n", "import {\n NoValueType,\n NO_VALUE,\n SimpleTwistyPropSource,\n} from \"../../TwistyProp\";\n\nexport const puzzleIDs = {\n \"3x3x3\": true, // default\n \"custom\": true,\n \"2x2x2\": true,\n \"4x4x4\": true,\n \"5x5x5\": true,\n \"6x6x6\": true,\n \"7x7x7\": true,\n \"40x40x40\": true,\n \"megaminx\": true,\n \"pyraminx\": true,\n \"square1\": true,\n \"clock\": true,\n \"skewb\": true,\n \"fto\": true,\n \"gigaminx\": true,\n \"master_tetraminx\": true,\n \"kilominx\": true,\n \"redi_cube\": true,\n};\nexport type PuzzleID = keyof typeof puzzleIDs;\n\n// TODO: Ideally we'd use `null` to mean \"no value\", but `null` has a special meaning\n// for `TwistyProp` and might mess with caching.\n// https://github.com/cubing/cubing.js/blob/63b0a55b83963f68410bb117a2e481052a07e086/src/cubing/twisty/model/TwistyProp.ts#L189-L189\nexport class PuzzleIDRequestProp extends SimpleTwistyPropSource<\n PuzzleID | NoValueType\n> {\n getDefaultValue(): PuzzleID | NoValueType {\n return NO_VALUE;\n }\n}\n", "import type { PuzzleDescriptionString } from \"../../../../../puzzle-geometry/PGPuzzles\";\nimport {\n cube3x3x3,\n experimentalCustomPGPuzzleLoader,\n PuzzleLoader,\n puzzles,\n} from \"../../../../../puzzles\";\nimport { NoValueType, NO_VALUE, TwistyPropDerived } from \"../../TwistyProp\";\nimport type { PuzzleID } from \"./PuzzleIDRequestProp\";\n8;\ninterface PuzzleLoaderPropInputs {\n puzzleIDRequest: PuzzleID | NoValueType;\n puzzleDescriptionRequest: PuzzleDescriptionString | NoValueType;\n}\n\nexport class PuzzleLoaderProp extends TwistyPropDerived<\n PuzzleLoaderPropInputs,\n PuzzleLoader\n> {\n derive(inputs: PuzzleLoaderPropInputs): PuzzleLoader {\n if (inputs.puzzleIDRequest && inputs.puzzleIDRequest !== NO_VALUE) {\n const puzzleLoader = puzzles[inputs.puzzleIDRequest];\n if (!puzzleLoader) {\n this.userVisibleErrorTracker!.set({\n errors: [`Invalid puzzle ID: ${inputs.puzzleIDRequest}`],\n });\n }\n return puzzleLoader;\n }\n if (\n inputs.puzzleDescriptionRequest &&\n inputs.puzzleDescriptionRequest !== NO_VALUE\n ) {\n return experimentalCustomPGPuzzleLoader(inputs.puzzleDescriptionRequest);\n }\n return cube3x3x3;\n }\n}\n", "import type { ButtonCommand } from \"../../../views/control-panel/TwistyButtons\";\nimport type { PlayingInfo } from \"./PlayingInfoProp\";\nimport type { DetailedTimelineInfo } from \"./DetailedTimelineInfoProp\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\n\ninterface ButtonAppearance {\n enabled: boolean;\n icon: string;\n title: string;\n}\nexport type ButtonAppearances = Record<ButtonCommand, ButtonAppearance>;\n\ninterface CoarseTimelineInfoInputs {\n playingInfo: PlayingInfo;\n detailedTimelineInfo: DetailedTimelineInfo;\n}\n\nexport interface CoarseTimelineInfo {\n playing: boolean;\n atStart: boolean;\n atEnd: boolean;\n}\n\n// This started as a version of `EffectiveTimestamp` without the actual\n// timestamp, to enable easier caching.\nexport class CoarseTimelineInfoProp extends TwistyPropDerived<\n CoarseTimelineInfoInputs,\n CoarseTimelineInfo\n> {\n derive(inputs: CoarseTimelineInfoInputs): CoarseTimelineInfo {\n return {\n playing: inputs.playingInfo.playing,\n atStart: inputs.detailedTimelineInfo.atStart,\n atEnd: inputs.detailedTimelineInfo.atEnd,\n };\n }\n\n canReuseValue(v1: CoarseTimelineInfo, v2: CoarseTimelineInfo): boolean {\n return (\n v1.playing === v2.playing &&\n v1.atStart === v2.atStart &&\n v1.atEnd === v2.atEnd\n );\n }\n}\n", "import type {\n MillisecondTimestamp,\n TimeRange,\n} from \"../../../controllers/AnimationTypes\";\nimport type { TimestampRequest } from \"./TimestampRequestProp\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\nimport type { SetupToLocation } from \"../puzzle/state/SetupAnchorProp\";\n\ninterface DetailedTimelineInfoInputs {\n timestampRequest: TimestampRequest;\n timeRange: TimeRange;\n setupAnchor: SetupToLocation;\n}\n\nexport interface DetailedTimelineInfo {\n timestamp: MillisecondTimestamp;\n timeRange: TimeRange; // TODO: Don't incluede this, and let fresh listeners listen to multiple inputs?\n // Note: `atStart` and `atEnd` can both be true. This is the case with the\n // default (empty) alg, which has a duration of 0 ms.\n atStart: boolean;\n atEnd: boolean;\n}\n\nexport class DetailedTimelineInfoProp extends TwistyPropDerived<\n DetailedTimelineInfoInputs,\n DetailedTimelineInfo\n> {\n derive(inputs: DetailedTimelineInfoInputs): DetailedTimelineInfo {\n let timestamp = this.#requestedTimestampToMilliseconds(inputs);\n let atStart: boolean = false;\n let atEnd: boolean = false;\n if (timestamp >= inputs.timeRange.end) {\n atEnd = true;\n timestamp = Math.min(inputs.timeRange.end, timestamp);\n }\n if (timestamp <= inputs.timeRange.start) {\n atStart = true;\n timestamp = Math.max(inputs.timeRange.start, timestamp);\n }\n return {\n timestamp,\n timeRange: inputs.timeRange,\n atStart,\n atEnd,\n };\n }\n\n #requestedTimestampToMilliseconds(\n inputs: DetailedTimelineInfoInputs,\n ): MillisecondTimestamp {\n switch (inputs.timestampRequest) {\n case \"start\":\n return inputs.timeRange.start;\n case \"end\":\n return inputs.timeRange.end;\n case \"anchor\":\n return inputs.setupAnchor === \"start\"\n ? inputs.timeRange.start\n : inputs.timeRange.end;\n case \"opposite-anchor\":\n return inputs.setupAnchor === \"start\"\n ? inputs.timeRange.end\n : inputs.timeRange.start;\n default:\n return inputs.timestampRequest;\n }\n }\n\n canReuse(v1: DetailedTimelineInfo, v2: DetailedTimelineInfo) {\n return (\n v1.timestamp === v2.timestamp &&\n v1.timeRange.start === v2.timeRange.start &&\n v1.timeRange.end === v2.timeRange.end &&\n v1.atStart === v2.atStart &&\n v1.atEnd === v2.atEnd\n );\n }\n}\n", "import { BoundaryType, Direction } from \"../../../controllers/AnimationTypes\";\nimport { TwistyPropSource } from \"../TwistyProp\";\n\nexport type SimpleDirection = Direction.Forwards | Direction.Backwards;\n\nexport interface PlayingInfo {\n playing: boolean;\n direction: SimpleDirection;\n untilBoundary: BoundaryType; // TODO: allows this to be optional in the setter?\n // TODO: Is `loop` responsible to add at this point? Maybe we should wait until we've figured out autoplay?\n // TODO: Combine `loop` into something with BoundaryType?\n loop: boolean;\n}\n\n// TODO: direction,\nexport class PlayingInfoProp extends TwistyPropSource<\n PlayingInfo,\n Partial<PlayingInfo>\n> {\n async getDefaultValue(): Promise<PlayingInfo> {\n return {\n direction: Direction.Forwards,\n playing: false,\n untilBoundary: BoundaryType.EntireTimeline,\n loop: false,\n };\n }\n\n async derive(\n newInfo: Partial<PlayingInfo>,\n oldValuePromise: Promise<PlayingInfo>,\n ): Promise<PlayingInfo> {\n const oldValue = await oldValuePromise;\n\n const newValue: PlayingInfo = Object.assign({}, oldValue);\n Object.assign(newValue, newInfo);\n return newValue;\n }\n\n canReuseValue(v1: PlayingInfo, v2: PlayingInfo) {\n return (\n v1.direction === v2.direction &&\n v1.playing === v2.playing &&\n v1.untilBoundary === v2.untilBoundary &&\n v1.loop === v2.loop\n );\n }\n}\n", "import { TwistyPropSource } from \"../TwistyProp\";\n\n// TODO: Pick a better name. `speed` is probably good, although that could mean\n// something else (e.g. shorter, faster moves but still with the same spacing).\nexport class TempoScaleProp extends TwistyPropSource<number, number> {\n getDefaultValue(): number {\n return 1;\n }\n\n derive(v: number): number {\n return v < 0 ? 1 : v;\n }\n}\n", "import type { MillisecondTimestamp } from \"../../../controllers/AnimationTypes\";\nimport { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nconst smartTimestamps = {\n \"start\": true,\n \"end\": true,\n \"anchor\": true,\n \"opposite-anchor\": true,\n};\n\nexport type TimestampRequest =\n | MillisecondTimestamp\n | keyof typeof smartTimestamps;\n\nexport class TimestampRequestProp extends SimpleTwistyPropSource<TimestampRequest> {\n getDefaultValue(): TimestampRequest {\n return \"opposite-anchor\";\n }\n\n // TODO: Support `Promise`\n set(v: TimestampRequest) {\n if (!this.validInput(v)) {\n // TODO: Generalize this to more props. How do we surface this? Throw an error and catch it from sync setters that call into this?\n return;\n }\n super.set(v);\n }\n\n validInput(v: TimestampRequest): boolean {\n if (typeof v === \"number\") {\n return true;\n }\n if (smartTimestamps[v]) {\n return true;\n }\n return false;\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nexport const backViewLayouts = {\n \"none\": true, // default\n \"side-by-side\": true,\n \"top-right\": true,\n};\nexport type BackViewLayout = keyof typeof backViewLayouts;\n\nexport type BackViewLayoutWithAuto = BackViewLayout | \"auto\";\n\nexport class BackViewProp extends SimpleTwistyPropSource<BackViewLayoutWithAuto> {\n getDefaultValue(): BackViewLayoutWithAuto {\n return \"auto\";\n }\n}\n", "import type { TimeRange } from \"../../../controllers/AnimationTypes\";\nimport type { AlgIndexer } from \"../../../controllers/indexer/AlgIndexer\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\n\nexport class TimeRangeProp extends TwistyPropDerived<\n { indexer: AlgIndexer },\n TimeRange\n> {\n derive(inputs: { indexer: AlgIndexer }): TimeRange {\n return {\n start: 0,\n end: inputs.indexer.algDuration(),\n };\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nexport const viewerLinkPages = {\n \"twizzle\": true, // default\n \"experimental-twizzle-explorer\": true,\n \"none\": true,\n};\nexport type ViewerLinkPage = keyof typeof viewerLinkPages;\nexport type ViewerLinkPageWithAuto = ViewerLinkPage | \"auto\";\n\nexport class ViewerLinkProp extends SimpleTwistyPropSource<ViewerLinkPageWithAuto> {\n getDefaultValue(): ViewerLinkPageWithAuto {\n return \"auto\";\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\n// TODO: turn these maps into lists?\nexport const visualizationFormats = {\n \"3D\": true, // default\n \"2D\": true,\n \"experimental-2D-LL\": true, // TODO\n \"PG3D\": true,\n};\nexport type VisualizationFormat = keyof typeof visualizationFormats;\nexport type VisualizationFormatWithAuto = VisualizationFormat | \"auto\";\n\nexport class VisualizationFormatProp extends SimpleTwistyPropSource<VisualizationFormatWithAuto> {\n getDefaultValue(): VisualizationFormatWithAuto {\n return \"auto\";\n }\n}\n", "import type { VisualizationFormatWithAuto } from \"./VisualizationProp\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\nimport type { PuzzleID } from \"../../..\";\n\ntype VisualizationStrategyPropInputs = {\n visualizationRequest: VisualizationFormatWithAuto;\n puzzleID: PuzzleID;\n};\n\nexport type VisualizationStrategy =\n | \"Cube3D\"\n | \"2D\"\n | \"experimental-2D-LL\"\n | \"PG3D\";\n\nexport class VisualizationStrategyProp extends TwistyPropDerived<\n VisualizationStrategyPropInputs,\n VisualizationStrategy\n> {\n derive(inputs: VisualizationStrategyPropInputs): VisualizationStrategy {\n switch (inputs.puzzleID) {\n case \"clock\":\n case \"square1\":\n case \"kilominx\":\n case \"redi_cube\":\n return \"2D\";\n case \"3x3x3\":\n switch (inputs.visualizationRequest) {\n case \"auto\":\n case \"3D\":\n return \"Cube3D\";\n default:\n return inputs.visualizationRequest;\n }\n default:\n switch (inputs.visualizationRequest) {\n case \"auto\":\n case \"3D\":\n return \"PG3D\";\n case \"experimental-2D-LL\":\n return \"2D\";\n default:\n return inputs.visualizationRequest;\n }\n }\n }\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport type FoundationDisplay = \"auto\" | \"opaque\" | \"none\";\n\nexport class FoundationDisplayProp extends SimpleTwistyPropSource<FoundationDisplay> {\n getDefaultValue(): FoundationDisplay {\n return \"auto\";\n }\n}\n", "import type { Texture, TextureLoader } from \"three\";\nimport { THREEJS } from \"../../../../heavy-code-imports/3d\";\nimport { TwistyPropDerived } from \"../../TwistyProp\";\n\nlet cachedLoader: TextureLoader | null = null;\nasync function loader(): Promise<TextureLoader> {\n return (cachedLoader ??= new (await THREEJS).TextureLoader());\n}\n\ntype SpritePropInputs = {\n spriteURL: URL | null;\n};\n\n// TODO: Find a way to make the 3D elements own this, instead of the main `TwistyPlayerModel`.\nexport class SpriteProp extends TwistyPropDerived<\n SpritePropInputs,\n Texture | null\n> {\n async derive(inputs: SpritePropInputs): Promise<Texture | null> {\n const { spriteURL: textureURL } = inputs;\n if (textureURL === null) {\n return null;\n }\n // eslint-disable-next-line no-async-promise-executor\n return new Promise(async (resolve, _reject) => {\n const onLoadingError = (): void => {\n console.warn(\"Could not load sprite:\", textureURL.toString());\n resolve(null);\n };\n // TODO: provide a way to listen for errors?\n try {\n (await loader()).load(\n textureURL.toString(),\n resolve,\n onLoadingError,\n onLoadingError,\n );\n } catch (e) {\n onLoadingError();\n }\n });\n }\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport const dragInputModes = {\n auto: true,\n none: true,\n};\nexport type DragInputMode = keyof typeof dragInputModes;\n\nexport class DragInputProp extends SimpleTwistyPropSource<DragInputMode> {\n getDefaultValue(): DragInputMode {\n return \"auto\";\n }\n}\n", "import { SimpleTwistyPropSource } from \"../../TwistyProp\";\n\nexport const movePressInputNames = {\n auto: true,\n none: true,\n basic: true,\n};\nexport type MovePressInput = keyof typeof movePressInputNames;\n\nexport class MovePressInputProp extends SimpleTwistyPropSource<MovePressInput> {\n getDefaultValue(): MovePressInput {\n return \"auto\";\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\n\nexport const backgroundThemes = {\n checkered: true, // default\n none: true,\n};\nexport type BackgroundTheme = keyof typeof backgroundThemes;\n\nexport type BackgroundThemeWithAuto = BackgroundTheme | \"auto\";\n\nexport class BackgroundProp extends SimpleTwistyPropSource<BackgroundThemeWithAuto> {\n getDefaultValue(): BackgroundThemeWithAuto {\n return \"auto\";\n }\n}\n", "import { SimpleTwistyPropSource } from \"../TwistyProp\";\nimport type { CoordinateDegrees } from \"./OrbitCoordinatesRequestProp\";\n\n// Similar to https://alg.cubing.net/\nconst DEFAULT_LATITUDE_LIMIT = 35;\n\nexport class LatitudeLimitProp extends SimpleTwistyPropSource<CoordinateDegrees> {\n getDefaultValue(): CoordinateDegrees {\n return DEFAULT_LATITUDE_LIMIT;\n }\n}\n", "import { mod } from \"../../helpers\";\nimport { TwistyPropSource } from \"../TwistyProp\";\n\nexport type CoordinateDegrees = number;\n\nexport interface OrbitCoordinates {\n latitude: CoordinateDegrees;\n longitude: CoordinateDegrees;\n distance: number;\n}\n\nexport function orbitCoordinatesEqual(\n c1: OrbitCoordinates,\n c2: OrbitCoordinates,\n): boolean {\n return (\n c1.latitude === c2.latitude &&\n c1.longitude === c2.longitude &&\n c1.distance === c2.distance\n );\n}\n\n// TOOD: Check if freezing affects perf.\n// const DEFAULT_COORDINATES = Object.freeze({\n// latitude: 35,\n// longitude: 30,\n// distance: 6,\n// });\n\nexport type OrbitCoordinatesRequest = Partial<OrbitCoordinates> | \"auto\";\n\n// TODO: Put the \"auto\" calculations in a separate place.\nexport class OrbitCoordinatesRequestProp extends TwistyPropSource<\n OrbitCoordinatesRequest,\n Partial<OrbitCoordinates> | \"auto\"\n> {\n getDefaultValue(): OrbitCoordinatesRequest {\n return \"auto\";\n }\n\n canReuseValue(v1: OrbitCoordinates, v2: OrbitCoordinates) {\n return v1 === v2 || orbitCoordinatesEqual(v1, v2);\n }\n\n async derive(\n newCoordinates: Partial<OrbitCoordinates> | \"auto\",\n oldValuePromise: Promise<OrbitCoordinatesRequest>,\n ): Promise<OrbitCoordinatesRequest> {\n if (newCoordinates === \"auto\") {\n return \"auto\";\n }\n\n let oldValue = await oldValuePromise;\n if (oldValue === \"auto\") {\n oldValue = {};\n }\n\n const newValue: Partial<OrbitCoordinates> = Object.assign({}, oldValue);\n Object.assign(newValue, newCoordinates);\n\n if (typeof newValue.latitude !== \"undefined\") {\n newValue.latitude = Math.min(Math.max(newValue.latitude, -90), 90);\n }\n if (typeof newValue.longitude !== \"undefined\") {\n newValue.longitude = mod(newValue.longitude, 360, 180);\n }\n return newValue;\n }\n}\n", "import { DEGREES_PER_RADIAN } from \"../../../views/3D/TAU\";\nimport type { PuzzleID } from \"../puzzle/structure/PuzzleIDRequestProp\";\nimport { TwistyPropDerived } from \"../TwistyProp\";\nimport {\n CoordinateDegrees,\n OrbitCoordinates,\n orbitCoordinatesEqual,\n OrbitCoordinatesRequest,\n} from \"./OrbitCoordinatesRequestProp\";\nimport type { VisualizationStrategy } from \"./VisualizationStrategyProp\";\n\ninterface OrbitCoordinatesPropInputs {\n orbitCoordinatesRequest: OrbitCoordinatesRequest;\n latitudeLimit: CoordinateDegrees;\n puzzleID: PuzzleID;\n strategy: VisualizationStrategy;\n}\n\nexport class OrbitCoordinatesProp extends TwistyPropDerived<\n OrbitCoordinatesPropInputs,\n OrbitCoordinates\n> {\n canReuseValue(v1: OrbitCoordinates, v2: OrbitCoordinates) {\n return orbitCoordinatesEqual(v1, v2);\n }\n\n async derive(inputs: OrbitCoordinatesPropInputs): Promise<OrbitCoordinates> {\n if (inputs.orbitCoordinatesRequest === \"auto\") {\n return defaultCameraOrbitCoordinates(inputs.puzzleID, inputs.strategy);\n }\n\n const req: OrbitCoordinates = Object.assign(\n Object.assign(\n {},\n defaultCameraOrbitCoordinates(inputs.puzzleID, inputs.strategy),\n inputs.orbitCoordinatesRequest,\n ),\n );\n\n if (Math.abs(req.latitude) <= inputs.latitudeLimit) {\n return req;\n } else {\n const { latitude, longitude, distance } = req;\n // TODO: Should we re-normalize the request, so we don't depend on normalization in the input?\n return {\n latitude: inputs.latitudeLimit * Math.sign(latitude),\n longitude,\n distance,\n };\n }\n }\n}\n\n// const DEFAULT_CAMERA_Z = 5;\n// // Golden ratio is perfect for FTO and Megaminx.\n// const DEFAULT_CAMERA_Y = DEFAULT_CAMERA_Z * (2 / (1 + Math.sqrt(5)));\nexport const centeredCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: 31.717474411461005,\n longitude: 0,\n distance: 5.877852522924731,\n};\n\n// This is tuned so that the hint facelets for 3x3x3 always fit in the canvas.\nexport const cubeCube3DCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: 35,\n longitude: 30,\n distance: 6,\n};\n\n// This is tuned so that the hint facelets always fit in the canvas.\nexport const cubePG3DCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: 35,\n longitude: 30,\n distance: 6.25,\n};\n\nexport const megaminxCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: Math.atan(1 / 2) * DEGREES_PER_RADIAN,\n longitude: 0,\n distance: 6.7,\n};\n\nexport const pyraminxCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: 26.56505117707799,\n longitude: 0,\n distance: 6,\n};\n\nexport const cornerCameraOrbitCoordinates: OrbitCoordinates = {\n latitude: 35.264389682754654,\n longitude: 45,\n distance: 6.928203230275509,\n};\n\n// TODO\nexport function defaultCameraOrbitCoordinates(\n puzzleID: PuzzleID,\n strategy: VisualizationStrategy,\n): OrbitCoordinates {\n if (puzzleID[1] === \"x\") {\n if (strategy === \"Cube3D\") {\n return cubeCube3DCameraOrbitCoordinates;\n } else {\n return cubePG3DCameraOrbitCoordinates;\n }\n } else {\n switch (puzzleID) {\n case \"megaminx\":\n case \"gigaminx\":\n return megaminxCameraOrbitCoordinates;\n case \"pyraminx\":\n case \"master_tetraminx\":\n return pyraminxCameraOrbitCoordinates;\n case \"skewb\":\n return cubePG3DCameraOrbitCoordinates;\n default:\n return centeredCameraOrbitCoordinates;\n }\n }\n}\n// TODO: templatize\nexport interface ManagedAttribute<K> {\n string: string;\n value: K;\n setString(s: string): boolean;\n setValue(v: K): boolean;\n}\n", "import { URLProp } from \"./props/general/URLProp\";\nimport { FoundationDisplayProp } from \"./props/puzzle/display/FoundationDisplayProp\";\nimport { HintFaceletProp } from \"./props/puzzle/display/HintFaceletProp\";\nimport { SpriteProp } from \"./props/puzzle/display/SpriteProp\";\nimport { StickeringProp } from \"./props/puzzle/display/StickeringProp\";\nimport { DragInputProp } from \"./props/puzzle/state/DragInputProp\";\nimport { MovePressInputProp } from \"./props/puzzle/state/MovePressInputProp\";\nimport { BackgroundProp } from \"./props/viewer/BackgroundProp\";\nimport { LatitudeLimitProp } from \"./props/viewer/LatitudeLimit\";\nimport { OrbitCoordinatesProp } from \"./props/viewer/OrbitCoordinatesProp\";\nimport { OrbitCoordinatesRequestProp } from \"./props/viewer/OrbitCoordinatesRequestProp\";\nimport type { TwistyPlayerModel } from \"./TwistyPlayerModel\";\n\nexport class TwistySceneModel {\n // Depth 0\n background = new BackgroundProp();\n dragInput = new DragInputProp();\n foundationDisplay = new FoundationDisplayProp();\n foundationStickerSpriteURL = new URLProp();\n hintFacelet = new HintFaceletProp();\n hintStickerSpriteURL = new URLProp();\n latitudeLimit = new LatitudeLimitProp();\n movePressInput = new MovePressInputProp();\n orbitCoordinatesRequest: OrbitCoordinatesRequestProp =\n new OrbitCoordinatesRequestProp();\n stickering = new StickeringProp();\n\n // Depth 1\n foundationStickerSprite = new SpriteProp({\n spriteURL: this.foundationStickerSpriteURL,\n });\n\n hintStickerSprite = new SpriteProp({\n spriteURL: this.hintStickerSpriteURL,\n });\n\n // Depth 4\n orbitCoordinates: OrbitCoordinatesProp;\n\n constructor(public twistyPlayerModel: TwistyPlayerModel) {\n this.orbitCoordinates = new OrbitCoordinatesProp({\n orbitCoordinatesRequest: this.orbitCoordinatesRequest,\n latitudeLimit: this.latitudeLimit,\n puzzleID: twistyPlayerModel.puzzleID,\n strategy: twistyPlayerModel.visualizationStrategy,\n });\n }\n}\n", "import { arrayEquals } from \"./helpers\";\nimport { SimpleTwistyPropSource } from \"./props/TwistyProp\";\n\ninterface UserVisibleError {\n errors: string[];\n}\n\nconst EMPTY_ERRORS = { errors: [] };\n\nexport class UserVisibleErrorTracker extends SimpleTwistyPropSource<UserVisibleError> {\n override getDefaultValue(): UserVisibleError {\n return EMPTY_ERRORS;\n }\n\n reset() {\n this.set(this.getDefaultValue());\n }\n\n canReuseValue(_v1: UserVisibleError, _v2: UserVisibleError): boolean {\n return arrayEquals(_v1.errors, _v2.errors);\n }\n}\n", "import { experimentalAppendMove, Move } from \"../../alg\";\nimport { ArbitraryStringProp } from \"./props/general/ArbitraryStringProp\";\nimport { URLProp } from \"./props/general/URLProp\";\nimport { AlgProp } from \"./props/puzzle/state/AlgProp\";\nimport { AlgTransformationProp } from \"./props/puzzle/state/AlgTransformationProp\";\nimport { AnchorTransformationProp } from \"./props/puzzle/state/AnchorTransformationProp\";\nimport { CatchUpMoveProp } from \"./props/puzzle/state/CatchUpMoveProp\";\nimport { CurrentLeavesSimplifiedProp } from \"./props/puzzle/state/CurrentLeavesSimplified\";\nimport { CurrentMoveInfoProp } from \"./props/puzzle/state/CurrentMoveInfoProp\";\nimport { CurrentStateProp as CurrentStateProp } from \"./props/puzzle/state/CurrentStateProp\";\nimport { IndexerConstructorProp } from \"./props/puzzle/state/IndexerConstructorProp\";\nimport { IndexerConstructorRequestProp } from \"./props/puzzle/state/IndexerConstructorRequestProp\";\nimport { IndexerProp } from \"./props/puzzle/state/IndexerProp\";\nimport { LegacyPositionProp } from \"./props/puzzle/state/LegacyPositionProp\";\nimport { NaiveMoveCountProp } from \"./props/puzzle/state/NaiveMoveCountProp\";\nimport { PuzzleAlgProp } from \"./props/puzzle/state/PuzzleAlgProp\";\nimport { SetupAnchorProp } from \"./props/puzzle/state/SetupAnchorProp\";\nimport { SetupTransformationProp } from \"./props/puzzle/state/SetupTransformationProp\";\nimport { KPuzzleProp } from \"./props/puzzle/structure/KPuzzleProp\";\nimport { PGPuzzleDescriptionStringProp } from \"./props/puzzle/structure/PuzzleDescriptionProp\";\nimport { PuzzleIDProp } from \"./props/puzzle/structure/PuzzleIDProp\";\nimport { PuzzleIDRequestProp } from \"./props/puzzle/structure/PuzzleIDRequestProp\";\nimport { PuzzleLoaderProp } from \"./props/puzzle/structure/PuzzleLoaderProp\";\nimport { CoarseTimelineInfoProp } from \"./props/timeline/CoarseTimelineInfoProp\";\nimport { DetailedTimelineInfoProp } from \"./props/timeline/DetailedTimelineInfoProp\";\nimport { PlayingInfoProp } from \"./props/timeline/PlayingInfoProp\";\nimport { TempoScaleProp } from \"./props/timeline/TempoScaleProp\";\nimport { TimestampRequestProp } from \"./props/timeline/TimestampRequestProp\";\nimport { NO_VALUE } from \"./props/TwistyProp\";\nimport { BackViewProp } from \"./props/viewer/BackViewProp\";\nimport { ButtonAppearanceProp } from \"./props/viewer/ButtonAppearanceProp\";\nimport { ControlPanelProp } from \"./props/viewer/ControlPanelProp\";\nimport { TimeRangeProp } from \"./props/viewer/TimeRangeProp\";\nimport { ViewerLinkProp } from \"./props/viewer/ViewerLinkProp\";\nimport { VisualizationFormatProp } from \"./props/viewer/VisualizationProp\";\nimport { VisualizationStrategyProp } from \"./props/viewer/VisualizationStrategyProp\";\nimport { TwistySceneModel } from \"./TwistySceneModel\";\nimport { UserVisibleErrorTracker } from \"./UserVisibleErrorTracker\";\n\nexport class TwistyPlayerModel {\n // TODO: incorporate error handling into the entire prop graph.\n // TODO: Make this something that can't get confused with normal props?\n userVisibleErrorTracker = new UserVisibleErrorTracker();\n\n // TODO: Redistribute and group props with controllers.\n\n // Depth 0\n alg = new AlgProp();\n backView = new BackViewProp();\n controlPanel = new ControlPanelProp();\n catchUpMove = new CatchUpMoveProp();\n indexerConstructorRequest = new IndexerConstructorRequestProp();\n playingInfo = new PlayingInfoProp();\n puzzleDescriptionRequest = new PGPuzzleDescriptionStringProp();\n puzzleIDRequest = new PuzzleIDRequestProp();\n setupAnchor = new SetupAnchorProp();\n setupAlg = new AlgProp();\n setupTransformation = new SetupTransformationProp();\n tempoScale = new TempoScaleProp();\n timestampRequest = new TimestampRequestProp();\n viewerLink = new ViewerLinkProp();\n visualizationFormat = new VisualizationFormatProp();\n // Metadata\n title = new ArbitraryStringProp();\n videoURL = new URLProp();\n competitionID = new ArbitraryStringProp();\n\n // Depth 1\n puzzleLoader = new PuzzleLoaderProp(\n {\n puzzleIDRequest: this.puzzleIDRequest,\n puzzleDescriptionRequest: this.puzzleDescriptionRequest,\n },\n this.userVisibleErrorTracker,\n );\n\n // Depth 2\n kpuzzle = new KPuzzleProp({ puzzleLoader: this.puzzleLoader });\n\n puzzleID = new PuzzleIDProp({ puzzleLoader: this.puzzleLoader });\n\n // Depth 3\n\n puzzleAlg = new PuzzleAlgProp({\n algWithIssues: this.alg,\n kpuzzle: this.kpuzzle,\n });\n\n puzzleSetupAlg = new PuzzleAlgProp({\n algWithIssues: this.setupAlg,\n kpuzzle: this.kpuzzle,\n });\n\n visualizationStrategy = new VisualizationStrategyProp({\n visualizationRequest: this.visualizationFormat,\n puzzleID: this.puzzleID,\n });\n\n // Depth 4\n indexerConstructor = new IndexerConstructorProp({\n alg: this.alg,\n puzzle: this.puzzleID,\n visualizationStrategy: this.visualizationStrategy,\n indexerConstructorRequest: this.indexerConstructorRequest,\n });\n\n moveCount = new NaiveMoveCountProp({ alg: this.puzzleAlg });\n\n setupAlgTransformation = new AlgTransformationProp({\n setupAlg: this.puzzleSetupAlg,\n kpuzzle: this.kpuzzle,\n });\n\n // Depth 5\n indexer = new IndexerProp({\n indexerConstructor: this.indexerConstructor,\n algWithIssues: this.puzzleAlg,\n kpuzzle: this.kpuzzle,\n });\n\n // Depth 6\n anchorTransformation = new AnchorTransformationProp({\n setupTransformation: this.setupTransformation,\n setupAnchor: this.setupAnchor,\n setupAlgTransformation: this.setupAlgTransformation,\n indexer: this.indexer,\n });\n\n timeRange = new TimeRangeProp({\n indexer: this.indexer,\n });\n\n // Depth 7\n detailedTimelineInfo: DetailedTimelineInfoProp = new DetailedTimelineInfoProp(\n {\n timestampRequest: this.timestampRequest,\n timeRange: this.timeRange,\n setupAnchor: this.setupAnchor,\n },\n );\n\n // Depth 8\n coarseTimelineInfo = new CoarseTimelineInfoProp({\n detailedTimelineInfo: this.detailedTimelineInfo,\n playingInfo: this.playingInfo,\n });\n\n currentMoveInfo = new CurrentMoveInfoProp({\n indexer: this.indexer,\n detailedTimelineInfo: this.detailedTimelineInfo,\n catchUpMove: this.catchUpMove,\n });\n\n // Depth 9\n // TODO: Inline Twisty3D management.\n buttonAppearance = new ButtonAppearanceProp({\n coarseTimelineInfo: this.coarseTimelineInfo,\n viewerLink: this.viewerLink,\n });\n\n currentLeavesSimplified = new CurrentLeavesSimplifiedProp({\n currentMoveInfo: this.currentMoveInfo,\n });\n\n // Depth 10\n currentState = new CurrentStateProp({\n anchoredStart: this.anchorTransformation,\n currentLeavesSimplified: this.currentLeavesSimplified,\n indexer: this.indexer,\n });\n\n // Depth 11\n legacyPosition = new LegacyPositionProp({\n currentMoveInfo: this.currentMoveInfo,\n state: this.currentState,\n });\n\n twistySceneModel = new TwistySceneModel(this);\n\n public async twizzleLink(): Promise<string> {\n const [\n viewerLink,\n puzzleID,\n puzzleDescription,\n alg,\n setup,\n anchor,\n experimentalStickering,\n ] = await Promise.all([\n this.viewerLink.get(),\n this.puzzleID.get(),\n this.puzzleDescriptionRequest.get(),\n this.alg.get(),\n this.setupAlg.get(),\n this.setupAnchor.get(),\n this.twistySceneModel.stickering.get(),\n ]);\n\n const isExplorer = viewerLink === \"experimental-twizzle-explorer\";\n\n console.log({ isExplorer, viewerLink });\n\n const url = new URL(\n `https://alpha.twizzle.net/${isExplorer ? \"explore\" : \"edit\"}/`,\n );\n\n if (!alg.alg.experimentalIsEmpty()) {\n url.searchParams.set(\"alg\", alg.alg.toString());\n }\n if (!setup.alg.experimentalIsEmpty()) {\n url.searchParams.set(\"setup-alg\", setup.alg.toString());\n }\n if (anchor !== \"start\") {\n url.searchParams.set(\"setup-anchor\", anchor);\n }\n if (experimentalStickering !== \"full\") {\n url.searchParams.set(\"experimental-stickering\", experimentalStickering);\n }\n if (isExplorer && puzzleDescription !== NO_VALUE) {\n url.searchParams.set(\"puzzle-description\", puzzleDescription);\n } else if (puzzleID !== \"3x3x3\") {\n url.searchParams.set(\"puzzle\", puzzleID);\n }\n return url.toString();\n }\n\n // TODO: Animate the new move.\n experimentalAddMove(\n flexibleMove: Move | string,\n options: { coalesce?: boolean; mod?: number } = {},\n ): void {\n const move =\n typeof flexibleMove === \"string\" ? new Move(flexibleMove) : flexibleMove;\n (async () => {\n const alg = (await this.alg.get()).alg;\n const newAlg = experimentalAppendMove(alg, move, {\n coalesce: options?.coalesce,\n mod: options?.mod,\n });\n this.alg.set(newAlg);\n this.timestampRequest.set(\"end\");\n this.catchUpMove.set({\n move: move,\n amount: 0,\n });\n })();\n }\n\n // TODO: Remove after https://github.com/Odder/pyraminx.tips/pull/1 lands\n /** @deprecated */\n get playingInfoProp(): PlayingInfoProp {\n console.warn(\n \"Using deprecated prop: `playingInfoProp`. Please switch to: `playingInfo`\",\n );\n return this.playingInfo;\n }\n}\n", "import type { Alg } from \"../../alg\";\nimport type { PuzzleDescriptionString } from \"../../puzzle-geometry/PGPuzzles\";\nimport type { ExperimentalStickering, PuzzleID } from \"../../twisty\";\nimport type { BackgroundThemeWithAuto } from \"../model/props/viewer/BackgroundProp\";\nimport type { BackViewLayoutWithAuto } from \"../model/props/viewer/BackViewProp\";\nimport type { ControlPanelThemeWithAuto } from \"../model/props/viewer/ControlPanelProp\";\nimport type { HintFaceletStyleWithAuto } from \"../model/props/puzzle/display/HintFaceletProp\";\nimport type { IndexerStrategyName } from \"../model/props/puzzle/state/IndexerConstructorRequestProp\";\nimport type { TimestampRequest } from \"../model/props/timeline/TimestampRequestProp\";\nimport type { ViewerLinkPageWithAuto } from \"../model/props/viewer/ViewerLinkProp\";\nimport type { VisualizationFormatWithAuto } from \"../model/props/viewer/VisualizationProp\";\nimport { TwistyPlayerModel } from \"../model/TwistyPlayerModel\";\nimport type { MillisecondTimestamp } from \"../controllers/AnimationTypes\";\nimport { ManagedCustomElement } from \"./ManagedCustomElement\";\nimport type { MovePressInput } from \"../model/props/puzzle/state/MovePressInputProp\";\nimport type { SetupToLocation } from \"../model/props/puzzle/state/SetupAnchorProp\";\nimport type { DragInputMode } from \"../model/props/puzzle/state/DragInputProp\";\n\nfunction err(propName: string): Error {\n return new Error(\n `Cannot get \\`.${propName}\\` directly from a \\`TwistyPlayer\\`.`,\n );\n}\n\n// prettier-ignore\nexport abstract class TwistyPlayerSettable extends ManagedCustomElement {\n experimentalModel: TwistyPlayerModel = new TwistyPlayerModel();\n\n set alg(newAlg: Alg | string) { this.experimentalModel.alg.set(newAlg); }\n get alg(): never { throw err(\"alg\"); }\n\n set experimentalSetupAlg(newSetup: Alg | string) { this.experimentalModel.setupAlg.set(newSetup); }\n get experimentalSetupAlg(): never { throw err(\"setup\"); }\n\n set experimentalSetupAnchor(anchor: SetupToLocation) { this.experimentalModel.setupAnchor.set(anchor); }\n get experimentalSetupAnchor(): never { throw err(\"anchor\"); }\n\n set puzzle(puzzleID: PuzzleID) { this.experimentalModel.puzzleIDRequest.set(puzzleID); }\n get puzzle(): never { throw err(\"puzzle\"); }\n\n set experimentalPuzzleDescription(puzzleDescription: PuzzleDescriptionString) { this.experimentalModel.puzzleDescriptionRequest.set(puzzleDescription); }\n get experimentalPuzzleDescription(): never { throw err(\"experimentalPuzzleDescription\"); }\n\n set timestamp(timestamp: TimestampRequest) { this.experimentalModel.timestampRequest.set(timestamp); }\n get timestamp(): never { throw err(\"timestamp\"); }\n\n set hintFacelets(hintFaceletStyle: HintFaceletStyleWithAuto) { this.experimentalModel.twistySceneModel.hintFacelet.set(hintFaceletStyle); }\n get hintFacelets(): never { throw err(\"hintFacelets\"); }\n\n set experimentalStickering(stickering: ExperimentalStickering) { this.experimentalModel.twistySceneModel.stickering.set(stickering); }\n get experimentalStickering(): never { throw err(\"stickering\"); }\n\n set backView(backView: BackViewLayoutWithAuto) { this.experimentalModel.backView.set(backView); }\n get backView(): never { throw err(\"backView\"); }\n\n set background(backgroundTheme: BackgroundThemeWithAuto) { this.experimentalModel.twistySceneModel.background.set(backgroundTheme); }\n get background(): never { throw err(\"background\"); }\n\n set controlPanel(newControlPanel: ControlPanelThemeWithAuto) { this.experimentalModel.controlPanel.set(newControlPanel); }\n get controlPanel(): never { throw err(\"controlPanel\"); }\n\n set visualization(visualizationFormat: VisualizationFormatWithAuto) { this.experimentalModel.visualizationFormat.set(visualizationFormat); }\n get visualization(): never { throw err(\"visualization\"); }\n\n set experimentalTitle(title: string | null) { this.experimentalModel.title.set(title); }\n get experimentalTitle(): never { throw err(\"experimentalTitle\"); }\n\n set experimentalVideoURL(videoURL: string | null) { this.experimentalModel.videoURL.set(videoURL); }\n get experimentalVideoURL(): never { throw err(\"experimentalVideoURL\"); }\n\n set experimentalCompetitionID(competitionID: string | null) { this.experimentalModel.competitionID.set(competitionID); }\n get experimentalCompetitionID(): never { throw err(\"experimentalCompetitionID\"); }\n\n set viewerLink(viewerLinkPage: ViewerLinkPageWithAuto) { this.experimentalModel.viewerLink.set(viewerLinkPage); }\n get viewerLink(): never { throw err(\"viewerLink\"); }\n\n set experimentalMovePressInput(movePressInput: MovePressInput) { this.experimentalModel.twistySceneModel.movePressInput.set(movePressInput); }\n get experimentalMovePressInput(): never { throw err(\"experimentalMovePressInput\"); }\n\n set cameraLatitude(latitude: number) { this.experimentalModel.twistySceneModel.orbitCoordinatesRequest.set({ latitude }); }\n get cameraLatitude(): never { throw err(\"cameraLatitude\"); }\n\n set cameraLongitude(longitude: number) { this.experimentalModel.twistySceneModel.orbitCoordinatesRequest.set({ longitude }); }\n get cameraLongitude(): never { throw err(\"cameraLongitude\"); }\n\n set cameraDistance(distance: number) { this.experimentalModel.twistySceneModel.orbitCoordinatesRequest.set({ distance }); }\n get cameraDistance(): never { throw err(\"cameraDistance\"); }\n\n set cameraLatitudeLimit(latitudeLimit: number) { this.experimentalModel.twistySceneModel.latitudeLimit.set(latitudeLimit); }\n get cameraLatitudeLimit(): never { throw err(\"cameraLatitudeLimit\"); }\n\n set indexer(indexer: IndexerStrategyName) { this.experimentalModel.indexerConstructorRequest.set(indexer); }\n get indexer(): never { throw err(\"indexer\"); }\n\n set tempoScale(newTempoScale: number) { this.experimentalModel.tempoScale.set(newTempoScale); }\n get tempoScale(): never { throw err(\"tempoScale\"); }\n\n set experimentalSprite(url: string | URL) { this.experimentalModel.twistySceneModel.foundationStickerSpriteURL.set(url); }\n get experimentalSprite(): never { throw err(\"experimentalSprite\"); }\n\n set experimentalHintSprite(url: string | URL) { this.experimentalModel.twistySceneModel.hintStickerSpriteURL.set(url); }\n get experimentalHintSprite(): never { throw err(\"experimentalHintSprite\"); }\n\n set experimentalDragInput(dragInputMode: DragInputMode) { this.experimentalModel.twistySceneModel.dragInput.set(dragInputMode); }\n get experimentalDragInput(): never { throw err(\"experimentalDragInput\"); }\n\n experimentalGet = new ExperimentalGetters(this.experimentalModel)\n}\n\nclass ExperimentalGetters {\n constructor(private model: TwistyPlayerModel) {}\n\n async alg(): Promise<Alg> {\n return (await this.model.alg.get()).alg;\n }\n\n async setupAlg(): Promise<Alg> {\n return (await this.model.setupAlg.get()).alg;\n }\n\n puzzleID(): Promise<PuzzleID> {\n return this.model.puzzleID.get();\n }\n\n async timestamp(): Promise<MillisecondTimestamp> {\n return (await this.model.detailedTimelineInfo.get()).timestamp;\n }\n}\n", "import type { ExperimentalStickering } from \"..\";\nimport type { Alg, Move } from \"../../alg\";\nimport type { PuzzleDescriptionString } from \"../../puzzle-geometry/PGPuzzles\";\nimport type { TwistyAnimationControllerDelegate } from \"../controllers/TwistyAnimationController\";\nimport { TwistyPlayerController } from \"../controllers/TwistyPlayerController\";\nimport type { HintFaceletStyleWithAuto } from \"../model/props/puzzle/display/HintFaceletProp\";\nimport type { DragInputMode } from \"../model/props/puzzle/state/DragInputProp\";\nimport type { MovePressInput } from \"../model/props/puzzle/state/MovePressInputProp\";\nimport type { SetupToLocation } from \"../model/props/puzzle/state/SetupAnchorProp\";\nimport type { PuzzleID } from \"../model/props/puzzle/structure/PuzzleIDRequestProp\";\nimport type { BackgroundThemeWithAuto } from \"../model/props/viewer/BackgroundProp\";\nimport type { BackViewLayoutWithAuto } from \"../model/props/viewer/BackViewProp\";\nimport {\n ControlPanelThemeWithAuto,\n controlsLocations,\n} from \"../model/props/viewer/ControlPanelProp\";\nimport type { ViewerLinkPageWithAuto } from \"../model/props/viewer/ViewerLinkProp\";\nimport type { VisualizationFormatWithAuto } from \"../model/props/viewer/VisualizationProp\";\nimport type { VisualizationStrategy } from \"../model/props/viewer/VisualizationStrategyProp\";\nimport { Twisty2DSceneWrapper } from \"./2D/Twisty2DSceneWrapper\";\nimport type { PG3D } from \"./3D/puzzles/PG3D\";\nimport { Twisty3DSceneWrapper } from \"./3D/Twisty3DSceneWrapper\";\nimport { ClassListManager } from \"./ClassListManager\";\nimport { TwistyButtons } from \"./control-panel/TwistyButtons\";\nimport { TwistyScrubber } from \"./control-panel/TwistyScrubber\";\nimport { customElementsShim } from \"./node-custom-element-shims\";\nimport { downloadURL, getDefaultFilename, screenshot } from \"./screenshot\";\nimport { twistyPlayerCSS } from \"./TwistyPlayer.css\";\nimport { TwistyPlayerSettable } from \"./TwistyPlayerSettable\";\n\nconst DATA_ATTRIBUTE_PREFIX = \"data-\";\n\n// TODO: I couldn't figure out how to use use more specific types. Ideally, we'd\n// enforce consistency with the model.\nexport const twistyPlayerAttributeMap = {\n // TODO: We assume each of these can be set using a string or will be automatically converted by JS (e.g. numbers). Can we enforce\n // that with types? Do we need to add a translation mechanism for things we\n // don't want to leave settable as strings?\n // TODO: Enum validation.\n\n // Alg\n \"alg\": \"alg\",\n \"experimental-setup-alg\": \"experimentalSetupAlg\",\n\n // String-based\n \"experimental-setup-anchor\": \"experimentalSetupAnchor\",\n \"puzzle\": \"puzzle\",\n \"experimental-puzzle-description\": \"experimentalPuzzleDescription\",\n \"visualization\": \"visualization\",\n \"hint-facelets\": \"hintFacelets\",\n \"experimental-stickering\": \"experimentalStickering\",\n \"background\": \"background\",\n \"control-panel\": \"controlPanel\",\n \"back-view\": \"backView\",\n // \"indexer\": \"indexer\",\n \"viewer-link\": \"viewerLink\",\n \"experimental-move-press-input\": \"experimentalMovePressInput\",\n \"experimental-drag-input\": \"experimentalDragInput\",\n\n // Metadata\n \"experimental-title\": \"experimentalTitle\",\n \"experimental-video-url\": \"experimentalVideoURL\",\n \"experimental-competition-id\": \"experimentalCompetitionID\",\n\n // Number-based\n \"camera-latitude\": \"cameraLatitude\",\n \"camera-longitude\": \"cameraLongitude\",\n \"camera-distance\": \"cameraDistance\",\n \"camera-latitude-limit\": \"cameraLatitudeLimit\",\n \"tempo-scale\": \"tempoScale\",\n\n // URL-based\n \"experimental-sprite\": \"experimentalSprite\",\n \"experimental-hint-sprite\": \"experimentalHintSprite\",\n};\n\nexport type TwistyPlayerAttribute = keyof typeof twistyPlayerAttributeMap;\n\nconst configKeys: Record<TwistyPlayerAttribute, true> = Object.fromEntries(\n Object.values(twistyPlayerAttributeMap).map((s) => [s, true]),\n) as any;\n\n// TODO: Find a way to share this def with `attributeMap`.\nexport interface TwistyPlayerConfig {\n // Alg\n alg?: Alg | string;\n experimentalSetupAlg?: Alg | string;\n\n // String-based\n experimentalSetupAnchor?: SetupToLocation; // TODO: \"auto\"\n puzzle?: PuzzleID;\n experimentalPuzzleDescription?: PuzzleDescriptionString;\n visualization?: VisualizationFormatWithAuto;\n hintFacelets?: HintFaceletStyleWithAuto;\n experimentalStickering?: ExperimentalStickering;\n background?: BackViewLayoutWithAuto;\n controlPanel?: ControlPanelThemeWithAuto;\n backView?: BackViewLayoutWithAuto;\n // \"indexer\"?: \"indexer\";\n viewerLink?: ViewerLinkPageWithAuto;\n experimentalMovePressInput?: MovePressInput;\n experimentalDragInput?: DragInputMode;\n\n // Metadata\n experimentalTitle?: string | null;\n experimentalVideoURL?: string;\n experimentalCompetitionID?: string;\n\n // Number-based\n cameraLatitude?: number;\n cameraLongitude?: number;\n cameraDistance?: number;\n cameraLatitudeLimit?: number;\n tempoScale?: number;\n\n // URL-based\n experimentalSprite?: string | null;\n experimentalHintSprite?: string | null;\n}\n\n/**\n * TwistyPlayer is the heart of `cubing.js`. It can be used to display a puzzle on a web page like this:\n *\n * <script src=\"path/to/cubing/twisty\" type=\"module\"></script>\n * <twisty-player alg=\"R U R'\"></twisty-player>\n *\n * You can also construct it directly in JavaScript:\n *\n * import { TwistyPlayer } from \"cubing/twisty\";\n * const twistyPlayer = new TwistyPlayer({alg: \"R U R'\"});\n * // Once the page has loaded, you can do this:\n * document.body.appendChild(twistyPlayer);\n *\n * See {@link https://js.cubing.net/cubing/} for more examples.\n */\nexport class TwistyPlayer\n extends TwistyPlayerSettable\n implements TwistyAnimationControllerDelegate\n{\n controller: TwistyPlayerController = new TwistyPlayerController(\n this.experimentalModel,\n this,\n );\n\n buttons: TwistyButtons;\n\n experimentalCanvasClickCallback: (...args: any) => void = () => {};\n // #onCanvasClick() {\n\n // }\n\n constructor(config: TwistyPlayerConfig = {}) {\n super();\n\n // TODO: double-check that these are all getting set sync without causing extra work.\n for (const [propName, value] of Object.entries(config)) {\n if (!configKeys[propName as TwistyPlayerAttribute]) {\n console.warn(`Invalid config passed to TwistyPlayer: ${propName}`);\n break;\n }\n (this as any)[propName] = value;\n }\n }\n\n #controlsManager: ClassListManager<ControlPanelThemeWithAuto> =\n new ClassListManager<ControlPanelThemeWithAuto>(\n this,\n \"controls-\",\n ([\"auto\"] as ControlPanelThemeWithAuto[]).concat(\n Object.keys(controlsLocations) as ControlPanelThemeWithAuto[],\n ),\n );\n\n #visualizationWrapperElem = document.createElement(\"div\"); // TODO: Better pattern.\n #errorElem = document.createElement(\"div\"); // TODO: Better pattern.\n #alreadyConnected = false; // TODO: support resetting\n async connectedCallback(): Promise<void> {\n if (this.#alreadyConnected) {\n return;\n }\n this.#alreadyConnected = true;\n this.addCSS(twistyPlayerCSS);\n\n this.addElement(this.#visualizationWrapperElem).classList.add(\n \"visualization-wrapper\",\n );\n this.addElement(this.#errorElem).classList.add(\"error-elem\");\n this.#errorElem.textContent = \"Error\";\n this.experimentalModel.userVisibleErrorTracker.addFreshListener(\n (userVisibleError) => {\n const errorString: string | null = userVisibleError.errors[0] ?? null;\n this.contentWrapper.classList.toggle(\"error\", !!errorString);\n if (errorString) {\n this.#errorElem.textContent = errorString;\n }\n },\n );\n\n const scrubber = new TwistyScrubber(this.experimentalModel);\n this.contentWrapper.appendChild(scrubber);\n\n this.buttons = new TwistyButtons(\n this.experimentalModel,\n this.controller,\n this,\n );\n this.contentWrapper.appendChild(this.buttons);\n\n this.experimentalModel.twistySceneModel.background.addFreshListener(\n (backgroundTheme: BackgroundThemeWithAuto) => {\n this.contentWrapper.classList.toggle(\n \"checkered\",\n backgroundTheme !== \"none\",\n );\n },\n );\n\n this.experimentalModel.controlPanel.addFreshListener(\n (controlPanel: ControlPanelThemeWithAuto) => {\n this.#controlsManager.setValue(controlPanel);\n },\n );\n\n this.experimentalModel.visualizationStrategy.addFreshListener(\n this.#setVisualizationWrapper.bind(this),\n );\n\n this.experimentalModel.puzzleID.addFreshListener(this.flash.bind(this));\n }\n\n #flashLevel: \"auto\" | \"none\" = \"auto\";\n /** @deprecated */\n experimentalSetFlashLevel(newLevel: \"auto\" | \"none\"): void {\n this.#flashLevel = newLevel;\n }\n\n flash() {\n if (this.#flashLevel === \"auto\") {\n this.#visualizationWrapper?.animate([{ opacity: 0.25 }, { opacity: 1 }], {\n duration: 250,\n easing: \"ease-out\",\n });\n }\n }\n\n #visualizationWrapper: Twisty2DSceneWrapper | Twisty3DSceneWrapper | null =\n null;\n\n #visualizationStrategy: VisualizationStrategy | null = null;\n #setVisualizationWrapper(strategy: VisualizationStrategy): void {\n if (strategy !== this.#visualizationStrategy) {\n this.#visualizationWrapper?.remove();\n this.#visualizationWrapper?.disconnect();\n let newWrapper: Twisty2DSceneWrapper | Twisty3DSceneWrapper;\n switch (strategy) {\n case \"2D\":\n case \"experimental-2D-LL\":\n newWrapper = new Twisty2DSceneWrapper(\n this.experimentalModel.twistySceneModel,\n strategy,\n );\n break;\n case \"Cube3D\":\n case \"PG3D\":\n // TODO: Properly wire this up so we can set PG3D for the cube.\n newWrapper = new Twisty3DSceneWrapper(this.experimentalModel);\n break;\n default:\n throw new Error(\"Invalid visualization\");\n }\n this.#visualizationWrapperElem.appendChild(newWrapper);\n this.#visualizationWrapper = newWrapper;\n this.#visualizationStrategy = strategy;\n }\n }\n\n async experimentalCurrentCanvases(): Promise<HTMLCanvasElement[]> {\n this.connectedCallback();\n const wrapper = this.#visualizationWrapper;\n const canvases: HTMLCanvasElement[] = [];\n if (wrapper instanceof Twisty3DSceneWrapper) {\n const vantages = wrapper.experimentalVantages();\n for (const vantage of vantages) {\n canvases.push((await vantage.canvasInfo()).canvas);\n }\n }\n return canvases;\n }\n\n async experimentalPG3D(): Promise<PG3D | null> {\n this.connectedCallback();\n const wrapper = this.#visualizationWrapper;\n if (wrapper instanceof Twisty3DSceneWrapper) {\n wrapper;\n }\n return null;\n }\n\n jumpToStart(options?: { flash: boolean }): void {\n this.controller.jumpToStart(options);\n }\n\n jumpToEnd(options?: { flash: boolean }): void {\n this.controller.jumpToEnd(options);\n }\n\n play(): void {\n this.controller.togglePlay(true);\n }\n\n pause(): void {\n this.controller.togglePlay(false);\n }\n\n // Inspiration:\n // - https://developer.mozilla.org/en-US/docs/Web/API/Element/toggleAttribute (`force` argument)\n // - https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle (`force` argument)\n // We still provide `play()` and `pause()` individually for convenience, though.\n togglePlay(play?: boolean): void {\n this.controller.togglePlay(play);\n }\n\n // TODO: Animate the new move.\n experimentalAddMove(\n flexibleMove: Move | string,\n options: { coalesce?: boolean } = {},\n ): void {\n this.experimentalModel.experimentalAddMove(flexibleMove, options);\n }\n\n static get observedAttributes(): string[] {\n const observed = [];\n for (const key of Object.keys(twistyPlayerAttributeMap)) {\n observed.push(key, DATA_ATTRIBUTE_PREFIX + key);\n }\n return observed;\n }\n\n attributeChangedCallback(\n attributeName: string,\n _oldValue: string,\n newValue: string,\n ): void {\n if (attributeName.startsWith(\"data-\")) {\n attributeName = attributeName.slice(\"data-\".length);\n }\n const setterName =\n twistyPlayerAttributeMap[attributeName as TwistyPlayerAttribute];\n if (!setterName) {\n return;\n }\n\n (this as any)[setterName] = newValue;\n }\n\n // TODO: Make this more ergonomic and flexible.\n // TODO: dimensions.\n async experimentalScreenshot(options?: {\n width: number;\n height: number;\n }): Promise<string> {\n return (await screenshot(this.experimentalModel, options)).dataURL;\n }\n\n // TODO: Make this more ergonomic and flexible.\n // TODO: dimensions.\n async experimentalDownloadScreenshot(filename?: string): Promise<void> {\n if (\n [\"2D\", \"experimental-2D-LL\"].includes(\n await this.experimentalModel.visualizationStrategy.get(),\n )\n ) {\n // TODO: This has lots of async issues. It should also go into the screenshot impl file.\n const wrapper2D = this.#visualizationWrapper as Twisty2DSceneWrapper;\n const twisty2DPuzzle = await wrapper2D\n .currentTwisty2DPuzzleWrapper()!\n .twisty2DPuzzle();\n const str = new XMLSerializer().serializeToString(\n twisty2DPuzzle.svg.element,\n );\n const url = URL.createObjectURL(new Blob([str]));\n downloadURL(\n url,\n filename ?? (await getDefaultFilename(this.experimentalModel)),\n \"svg\",\n );\n } else {\n await (await screenshot(this.experimentalModel)).download(filename);\n }\n }\n}\n\ncustomElementsShim.define(\"twisty-player\", TwistyPlayer);\ndeclare global {\n interface HTMLElementTagNameMap {\n \"twisty-player\": TwistyPlayer;\n }\n}\n", "import { CSSSource } from \"./ManagedCustomElement\";\n\nexport const twistyAlgViewerCSS = new CSSSource(`\n:host {\n display: inline-grid;\n}\n\na:not(:hover) {\n color: inherit;\n text-decoration: none;\n}\n\ntwisty-alg-leaf-elem.twisty-alg-comment {\n color: rgba(0, 0, 0, 0.4);\n}\n\n.wrapper.current-move {\n background: rgba(66, 133, 244, 0.3);\n margin-left: -0.1em;\n margin-right: -0.1em;\n padding-left: 0.1em;\n padding-right: 0.1em;\n border-radius: 0.1em;\n}\n`);\n", "import {\n Alg,\n Commutator,\n Conjugate,\n experimentalDirect,\n ExperimentalIterationDirection,\n Grouping,\n LineComment,\n Move,\n Newline,\n Pause,\n TraversalDownUp,\n Unit,\n} from \"../../alg\";\nimport type { Parsed } from \"../../alg/parse\";\nimport type { AlgWithIssues } from \"../model/props/puzzle/state/AlgProp\";\nimport type { DetailedTimelineInfo } from \"../model/props/timeline/DetailedTimelineInfoProp\";\nimport type { MillisecondTimestamp } from \"../controllers/AnimationTypes\";\nimport type { CurrentMoveInfo } from \"../controllers/indexer/AlgIndexer\";\nimport { ManagedCustomElement } from \"./ManagedCustomElement\";\nimport {\n customElementsShim,\n HTMLElementShim,\n} from \"./node-custom-element-shims\";\nimport { twistyAlgViewerCSS } from \"./TwistyAlgViewer.css\";\nimport { TwistyPlayer } from \"./TwistyPlayer\";\n\nconst DEFAULT_OFFSET_MS = 250; // TODO: make this a fraction?\n\nclass DataDown {\n earliestMoveIndex: number;\n twistyAlgViewer: TwistyAlgViewer;\n direction: ExperimentalIterationDirection;\n}\n\nclass DataUp {\n moveCount: number;\n element: TwistyAlgWrapperElem | TwistyAlgLeafElem;\n}\n\nclass TwistyAlgLeafElem extends ManagedCustomElement {\n constructor(\n className: string,\n text: string,\n dataDown: DataDown,\n public algOrUnit: Alg | Unit,\n offsetIntoMove: boolean,\n clickable: boolean,\n ) {\n super({ mode: \"open\" });\n this.classList.add(className);\n\n this.addCSS(twistyAlgViewerCSS);\n if (clickable) {\n const anchor = this.contentWrapper.appendChild(\n document.createElement(\"a\"),\n );\n anchor.href = \"#\";\n anchor.textContent = text;\n\n anchor.addEventListener(\"click\", (e) => {\n e.preventDefault();\n dataDown.twistyAlgViewer.jumpToIndex(\n dataDown.earliestMoveIndex,\n offsetIntoMove,\n );\n });\n } else {\n this.contentWrapper.appendChild(\n document.createElement(\"span\"),\n ).textContent = text;\n }\n }\n\n pathToIndex(_index: number): (TwistyAlgWrapperElem | TwistyAlgLeafElem)[] {\n return [];\n }\n\n setCurrentMove(current: boolean) {\n this.contentWrapper.classList.toggle(\"current-move\", current);\n }\n}\n\ncustomElementsShim.define(\"twisty-alg-leaf-elem\", TwistyAlgLeafElem);\n\nclass TwistyAlgWrapperElem extends HTMLElementShim {\n private queue: (Element | Text)[] = [];\n\n constructor(className: string, public algOrUnit: Alg | Unit) {\n super();\n this.classList.add(className);\n }\n\n addString(str: string) {\n this.queue.push(document.createTextNode(str));\n }\n\n addElem(dataUp: DataUp): number {\n this.queue.push(dataUp.element);\n return dataUp.moveCount;\n }\n\n flushQueue(\n direction: ExperimentalIterationDirection = ExperimentalIterationDirection.Forwards,\n ): void {\n for (const node of maybeReverseList(this.queue, direction)) {\n this.append(node);\n }\n this.queue = [];\n }\n\n pathToIndex(_index: number): (TwistyAlgWrapperElem | TwistyAlgLeafElem)[] {\n return [];\n }\n}\n\ncustomElementsShim.define(\"twisty-alg-wrapper-elem\", TwistyAlgWrapperElem);\n\nfunction oppositeDirection(\n direction: ExperimentalIterationDirection,\n): ExperimentalIterationDirection {\n return direction === ExperimentalIterationDirection.Forwards\n ? ExperimentalIterationDirection.Backwards\n : ExperimentalIterationDirection.Forwards;\n}\n\nfunction updateDirectionByAmount(\n currentDirection: ExperimentalIterationDirection,\n amount: number,\n): ExperimentalIterationDirection {\n return amount < 0 ? oppositeDirection(currentDirection) : currentDirection;\n}\n\nfunction maybeReverseList<T>(\n l: T[],\n direction: ExperimentalIterationDirection,\n): T[] {\n if (direction === ExperimentalIterationDirection.Forwards) {\n return l;\n }\n // console.log(\"rev\", Array.from(l).reverse());\n // return Array.from(l).reverse();\n const copy = Array.from(l);\n copy.reverse();\n return copy;\n}\n\nclass AlgToDOMTree extends TraversalDownUp<DataDown, DataUp, DataUp> {\n public traverseAlg(alg: Alg, dataDown: DataDown): DataUp {\n let moveCount = 0;\n const element = new TwistyAlgWrapperElem(\"twisty-alg-alg\", alg); // TODO: pick a better class name.\n let first = true;\n for (const unit of experimentalDirect(alg.units(), dataDown.direction)) {\n if (!first) {\n element.addString(\" \");\n }\n first = false;\n moveCount += element.addElem(\n this.traverseUnit(unit, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction: dataDown.direction,\n }),\n );\n }\n element.flushQueue(dataDown.direction);\n return {\n moveCount: moveCount,\n element,\n };\n }\n\n public traverseGrouping(grouping: Grouping, dataDown: DataDown): DataUp {\n const square1Tuple = grouping.experimentalAsSquare1Tuple();\n // if (square1Tuplle) {\n\n // }\n\n const direction = updateDirectionByAmount(\n dataDown.direction,\n grouping.amount,\n );\n let moveCount = 0;\n const element = new TwistyAlgWrapperElem(\"twisty-alg-grouping\", grouping);\n element.addString(\"(\");\n\n if (square1Tuple) {\n moveCount += element.addElem({\n moveCount: 1,\n element: new TwistyAlgLeafElem(\n \"twisty-alg-move\", // TODO: Mark the tuple with a special class?\n square1Tuple[0].amount.toString(),\n dataDown,\n square1Tuple[0],\n true,\n true,\n ),\n });\n element.addString(\", \");\n moveCount += element.addElem({\n moveCount: 1,\n element: new TwistyAlgLeafElem(\n \"twisty-alg-move\", // TODO: Mark the tuple with a special class?\n square1Tuple[1].amount.toString(),\n dataDown,\n square1Tuple[1],\n true,\n true,\n ),\n });\n } else {\n moveCount += element.addElem(\n this.traverseAlg(grouping.alg, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction,\n }),\n );\n }\n\n element.addString(\")\" + grouping.experimentalRepetitionSuffix);\n element.flushQueue();\n return {\n moveCount: moveCount * Math.abs(grouping.amount),\n element,\n };\n }\n\n public traverseMove(move: Move, dataDown: DataDown): DataUp {\n const element = new TwistyAlgLeafElem(\n \"twisty-alg-move\",\n move.toString(),\n dataDown,\n move,\n true,\n true,\n );\n dataDown.twistyAlgViewer.highlighter.addMove(\n (move as Parsed<Move>).startCharIndex,\n element,\n );\n return {\n moveCount: 1,\n element,\n };\n }\n\n public traverseCommutator(\n commutator: Commutator,\n dataDown: DataDown,\n ): DataUp {\n let moveCount = 0;\n const element = new TwistyAlgWrapperElem(\n \"twisty-alg-commutator\",\n commutator,\n );\n element.addString(\"[\");\n element.flushQueue();\n const [first, second]: Alg[] = maybeReverseList(\n [commutator.A, commutator.B],\n dataDown.direction,\n );\n moveCount += element.addElem(\n this.traverseAlg(first, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction: dataDown.direction,\n }),\n );\n element.addString(\", \");\n moveCount += element.addElem(\n this.traverseAlg(second, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction: dataDown.direction,\n }),\n );\n element.flushQueue(dataDown.direction);\n element.addString(\"]\");\n element.flushQueue();\n return {\n moveCount: moveCount * 2,\n element,\n };\n }\n\n public traverseConjugate(conjugate: Conjugate, dataDown: DataDown): DataUp {\n let moveCount = 0;\n const element = new TwistyAlgWrapperElem(\"twisty-alg-conjugate\", conjugate);\n element.addString(\"[\");\n const aLen = element.addElem(\n this.traverseAlg(conjugate.A, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction: dataDown.direction,\n }),\n );\n moveCount += aLen;\n element.addString(\": \");\n moveCount += element.addElem(\n this.traverseAlg(conjugate.B, {\n earliestMoveIndex: dataDown.earliestMoveIndex + moveCount,\n twistyAlgViewer: dataDown.twistyAlgViewer,\n direction: dataDown.direction,\n }),\n );\n element.addString(\"]\");\n element.flushQueue();\n return {\n moveCount: moveCount + aLen,\n element,\n };\n }\n\n public traversePause(pause: Pause, dataDown: DataDown): DataUp {\n return {\n moveCount: 1,\n element: new TwistyAlgLeafElem(\n \"twisty-alg-pause\",\n \".\",\n dataDown,\n pause,\n true,\n true,\n ),\n };\n }\n\n public traverseNewline(newline: Newline, _dataDown: DataDown): DataUp {\n const element = new TwistyAlgWrapperElem(\"twisty-alg-newline\", newline);\n element.append(document.createElement(\"br\"));\n return {\n moveCount: 0,\n element,\n };\n }\n\n public traverseLineComment(\n lineComment: LineComment,\n dataDown: DataDown,\n ): DataUp {\n return {\n moveCount: 0,\n element: new TwistyAlgLeafElem(\n \"twisty-alg-line-comment\",\n `//${lineComment.text}`,\n dataDown,\n lineComment,\n false,\n false,\n ),\n };\n }\n}\n\nconst algToDOMTreeInstance = new AlgToDOMTree();\nconst algToDOMTree = algToDOMTreeInstance.traverseAlg.bind(\n algToDOMTreeInstance,\n) as (alg: Alg, dataDown: DataDown) => DataUp;\n\nclass MoveHighlighter {\n moveCharIndexMap: Map<number, TwistyAlgLeafElem> = new Map();\n currentElem: TwistyAlgLeafElem | null = null;\n\n addMove(charIndex: number, elem: TwistyAlgLeafElem): void {\n this.moveCharIndexMap.set(charIndex, elem);\n }\n\n set(move: Parsed<Move> | null): void {\n const newElem = move\n ? this.moveCharIndexMap.get(move.startCharIndex) ?? null\n : null;\n if (this.currentElem === newElem) {\n return;\n }\n this.currentElem?.classList.remove(\"twisty-alg-current-move\");\n this.currentElem?.setCurrentMove(false);\n newElem?.classList.add(\"twisty-alg-current-move\");\n newElem?.setCurrentMove(true);\n this.currentElem = newElem;\n }\n}\n\nexport class TwistyAlgViewer extends HTMLElementShim {\n highlighter: MoveHighlighter = new MoveHighlighter();\n #domTree: TwistyAlgWrapperElem | TwistyAlgLeafElem;\n #twistyPlayer: TwistyPlayer | null = null;\n lastClickTimestamp: number | null = null;\n constructor(options?: { twistyPlayer?: TwistyPlayer }) {\n super();\n if (options?.twistyPlayer) {\n this.twistyPlayer = options?.twistyPlayer;\n }\n }\n\n protected connectedCallback(): void {\n // nothing to do?\n }\n\n private setAlg(alg: Alg): void {\n this.#domTree = algToDOMTree(alg, {\n earliestMoveIndex: 0,\n twistyAlgViewer: this,\n direction: ExperimentalIterationDirection.Forwards,\n }).element;\n this.textContent = \"\";\n this.appendChild(this.#domTree);\n }\n\n get twistyPlayer(): TwistyPlayer | null {\n return this.#twistyPlayer;\n }\n\n set twistyPlayer(twistyPlayer: TwistyPlayer | null) {\n this.#setTwistyPlayer(twistyPlayer);\n }\n\n async #setTwistyPlayer(twistyPlayer: TwistyPlayer | null) {\n if (this.#twistyPlayer) {\n console.warn(\"twisty-player reassignment is not supported\");\n return;\n }\n if (twistyPlayer === null) {\n throw new Error(\"clearing twistyPlayer is not supported\");\n }\n this.#twistyPlayer = twistyPlayer;\n\n this.#twistyPlayer.experimentalModel.alg.addFreshListener(\n (algWithIssues: AlgWithIssues) => {\n this.setAlg(algWithIssues.alg);\n },\n );\n\n const sourceAlg = (await this.#twistyPlayer.experimentalModel.alg.get())\n .alg;\n // TODO: Use proper architecture instead of a heuristic to ensure we have a parsed alg annotated with char indices.\n const parsedAlg =\n \"startCharIndex\" in (sourceAlg as Partial<Parsed<Alg>>)\n ? sourceAlg\n : Alg.fromString(sourceAlg.toString());\n this.setAlg(parsedAlg);\n\n twistyPlayer.experimentalModel.currentMoveInfo.addFreshListener(\n (currentMoveInfo: CurrentMoveInfo) => {\n let moveInfo = currentMoveInfo.currentMoves[0];\n moveInfo ??= currentMoveInfo.movesStarting[0];\n moveInfo ??= currentMoveInfo.movesFinishing[0];\n if (!moveInfo) {\n this.highlighter.set(null);\n } else {\n const mainCurrentMove = moveInfo.move; // TODO\n this.highlighter.set(mainCurrentMove as Parsed<Move>);\n }\n },\n );\n\n twistyPlayer.experimentalModel.detailedTimelineInfo.addFreshListener(\n (detailedTimelineInfo: DetailedTimelineInfo) => {\n if (detailedTimelineInfo.timestamp !== this.lastClickTimestamp) {\n this.lastClickTimestamp = null;\n }\n },\n );\n }\n\n async jumpToIndex(index: number, offsetIntoMove: boolean): Promise<void> {\n // TODO: Fix async issues.\n const twistyPlayer = this.#twistyPlayer;\n if (twistyPlayer) {\n twistyPlayer.pause();\n const timestampPromise = (async (): Promise<MillisecondTimestamp> => {\n const indexer = await twistyPlayer.experimentalModel.indexer.get();\n const offset = offsetIntoMove ? DEFAULT_OFFSET_MS : 0;\n return (indexer.indexToMoveStartTimestamp(index) ?? -offset) + offset;\n })();\n twistyPlayer.experimentalModel.timestampRequest.set(\n await timestampPromise, // TODO\n );\n if (this.lastClickTimestamp === (await timestampPromise)) {\n twistyPlayer.play();\n this.lastClickTimestamp = null;\n } else {\n this.lastClickTimestamp = await timestampPromise;\n }\n }\n }\n\n protected async attributeChangedCallback(\n attributeName: string,\n _oldValue: string,\n newValue: string,\n ): Promise<void> {\n if (attributeName === \"for\") {\n const elem = document.getElementById(newValue);\n if (!elem) {\n console.warn(\"for= elem does not exist\");\n return;\n }\n await customElements.whenDefined(\"twisty-player\");\n if (!(elem instanceof TwistyPlayer)) {\n console.warn(\"for= elem is not a twisty-player\");\n return;\n }\n this.twistyPlayer = elem;\n }\n }\n\n static get observedAttributes(): string[] {\n return [\"for\"];\n }\n}\n\ncustomElementsShim.define(\"twisty-alg-viewer\", TwistyAlgViewer);\ndeclare global {\n interface HTMLElementTagNameMap {\n \"twisty-alg-viewer\": TwistyAlgViewer;\n }\n}\n", "import {\n Alg,\n Commutator,\n Conjugate,\n Grouping,\n LineComment,\n Move,\n Newline,\n Pause,\n TraversalDownUp,\n} from \"../../../alg\";\nimport type { Parsed } from \"../../../alg/parse\";\nimport type { AnimatedLeafUnit } from \"../../controllers/indexer/simultaneous-moves/simul-moves\";\n\nexport type AnimatedLeafUnitInfo = {\n leaf: Parsed<AnimatedLeafUnit>;\n idx: number;\n};\nexport type OrderedLeafTokens = AnimatedLeafUnitInfo[];\n\ninterface DataUp {\n tokens: OrderedLeafTokens;\n numLeavesInside: number;\n}\n\ninterface DataDown {\n numMovesSofar: number;\n}\n\nclass LeafTokens extends TraversalDownUp<DataDown, DataUp> {\n public traverseAlg(alg: Alg, dataDown: DataDown): DataUp {\n const unitArrays: OrderedLeafTokens[] = [];\n let numMovesInside = 0;\n for (const unit of alg.units()) {\n const dataUp = this.traverseUnit(unit, {\n numMovesSofar: dataDown.numMovesSofar + numMovesInside,\n });\n unitArrays.push(dataUp.tokens);\n numMovesInside += dataUp.numLeavesInside;\n }\n return {\n tokens: Array.prototype.concat(...unitArrays),\n numLeavesInside: numMovesInside,\n };\n }\n\n public traverseGrouping(grouping: Grouping, dataDown: DataDown): DataUp {\n const dataUp = this.traverseAlg(grouping.alg, dataDown);\n return {\n tokens: dataUp.tokens,\n numLeavesInside: dataUp.numLeavesInside * grouping.amount,\n };\n }\n\n public traverseMove(move: Move, dataDown: DataDown): DataUp {\n return {\n tokens: [{ leaf: move as Parsed<Move>, idx: dataDown.numMovesSofar }],\n numLeavesInside: 1,\n }; // TODO: What if not parsed?\n }\n\n public traverseCommutator(\n commutator: Commutator,\n dataDown: DataDown,\n ): DataUp {\n const dataUpA = this.traverseAlg(commutator.A, dataDown);\n const dataUpB = this.traverseAlg(commutator.B, {\n numMovesSofar: dataDown.numMovesSofar + dataUpA.numLeavesInside,\n });\n return {\n tokens: dataUpA.tokens.concat(dataUpB.tokens),\n numLeavesInside: dataUpA.numLeavesInside * 2 + dataUpB.numLeavesInside,\n };\n }\n\n public traverseConjugate(conjugate: Conjugate, dataDown: DataDown): DataUp {\n const dataUpA = this.traverseAlg(conjugate.A, dataDown);\n const dataUpB = this.traverseAlg(conjugate.B, {\n numMovesSofar: dataDown.numMovesSofar + dataUpA.numLeavesInside,\n });\n return {\n tokens: dataUpA.tokens.concat(dataUpB.tokens),\n numLeavesInside:\n dataUpA.numLeavesInside * 2 + dataUpB.numLeavesInside * 2,\n };\n }\n\n public traversePause(pause: Pause, dataDown: DataDown): DataUp {\n return {\n tokens: [{ leaf: pause as Parsed<Pause>, idx: dataDown.numMovesSofar }],\n numLeavesInside: 1,\n }; // TODO: What if not parsed?\n }\n\n public traverseNewline(_newline: Newline, _dataDown: DataDown): DataUp {\n return {\n tokens: [],\n numLeavesInside: 0,\n };\n }\n\n public traverseLineComment(\n _comment: LineComment,\n _dataDown: DataDown,\n ): DataUp {\n return {\n tokens: [],\n numLeavesInside: 0,\n };\n }\n}\n\nconst leafTokensInstance = new LeafTokens();\nexport const leafTokens = leafTokensInstance.traverseAlg.bind(\n leafTokensInstance,\n) as (alg: Parsed<Alg>, dataDown: DataDown) => DataUp;\n", "// TODO: Move this?\n\nimport type { Alg } from \"../../../alg\";\nimport type { Parsed } from \"../../../alg/parse\";\nimport {\n AlgWithIssues,\n algWithIssuesFromString,\n} from \"../../model/props/puzzle/state/AlgProp\";\nimport {\n SimpleTwistyPropSource,\n TwistyPropDerived,\n TwistyPropSource,\n} from \"../../model/props/TwistyProp\";\nimport {\n AnimatedLeafUnitInfo,\n leafTokens,\n OrderedLeafTokens,\n} from \"./LeafTokens\";\n\nexport class TwistyAlgEditorValueProp extends SimpleTwistyPropSource<string> {\n getDefaultValue(): string {\n return \"\";\n }\n}\n\ninterface AlgEditorAlgWithIssuesPropInput {\n value: string;\n}\nclass AlgEditorAlgWithIssuesProp extends TwistyPropDerived<\n AlgEditorAlgWithIssuesPropInput,\n AlgWithIssues\n> {\n derive(input: AlgEditorAlgWithIssuesPropInput): AlgWithIssues {\n return algWithIssuesFromString(input.value);\n }\n\n // TODO: canReuse needs to take the source string into account.\n}\n\ninterface SelectionInfoPropInput {\n selectionStart: number;\n selectionEnd: number;\n}\ninterface SelectionInfo extends SelectionInfoPropInput {\n endChangedMostRecently: boolean;\n}\nexport class TwistyAlgEditorSelectionProp extends TwistyPropSource<\n SelectionInfo,\n SelectionInfoPropInput\n> {\n getDefaultValue() {\n return {\n selectionStart: 0,\n selectionEnd: 0,\n endChangedMostRecently: false,\n };\n }\n\n async derive(\n input: SelectionInfoPropInput,\n oldValue: Promise<SelectionInfo>,\n ): Promise<SelectionInfo> {\n const { selectionStart, selectionEnd } = input;\n const lastResult = await oldValue;\n const endChangedMostRecently =\n input.selectionStart === lastResult.selectionStart &&\n input.selectionEnd !== (await oldValue).selectionEnd;\n return {\n selectionStart,\n selectionEnd,\n endChangedMostRecently,\n };\n }\n}\n\ninterface TargetCharPropInputs {\n selectionInfo: SelectionInfo;\n}\n\nexport class TargetCharProp extends TwistyPropDerived<\n TargetCharPropInputs,\n number\n> {\n derive(inputs: TargetCharPropInputs) {\n return inputs.selectionInfo.endChangedMostRecently\n ? inputs.selectionInfo.selectionEnd\n : inputs.selectionInfo.selectionStart;\n }\n}\n\ninterface LeafTokensPropInputs {\n algWithIssues: AlgWithIssues;\n}\nclass LeafTokensProp extends TwistyPropDerived<\n LeafTokensPropInputs,\n OrderedLeafTokens\n> {\n derive(inputs: LeafTokensPropInputs): OrderedLeafTokens {\n return leafTokens(inputs.algWithIssues.alg as Parsed<Alg>, {\n numMovesSofar: 0,\n }).tokens;\n }\n}\n\ninterface LeafToHighlightPropInputs {\n targetChar: number;\n leafTokens: OrderedLeafTokens;\n}\ntype HighlightWhere = \"before\" | \"start\" | \"inside\" | \"end\" | \"after\";\nexport interface HighlightInfo {\n leafInfo: AnimatedLeafUnitInfo;\n where: HighlightWhere;\n}\nclass LeafToHighlightProp extends TwistyPropDerived<\n LeafToHighlightPropInputs,\n HighlightInfo | null\n> {\n derive(inputs: LeafToHighlightPropInputs): HighlightInfo | null {\n function withWhere(\n leafInfo: AnimatedLeafUnitInfo | null,\n ): HighlightInfo | null {\n if (leafInfo === null) {\n return null;\n }\n let where: HighlightWhere;\n if (inputs.targetChar < leafInfo.leaf.startCharIndex) {\n where = \"before\";\n } else if (inputs.targetChar === leafInfo.leaf.startCharIndex) {\n where = \"start\";\n } else if (inputs.targetChar < leafInfo.leaf.endCharIndex) {\n where = \"inside\";\n } else if (inputs.targetChar === leafInfo.leaf.endCharIndex) {\n where = \"end\";\n } else {\n where = \"after\";\n }\n return {\n leafInfo,\n where,\n };\n }\n\n let lastLeafInfo: AnimatedLeafUnitInfo | null = null;\n // TODO: binary search\n for (const leafInfo of inputs.leafTokens) {\n if (\n inputs.targetChar < leafInfo.leaf.startCharIndex &&\n lastLeafInfo !== null\n ) {\n return withWhere(lastLeafInfo);\n }\n if (inputs.targetChar <= leafInfo.leaf.endCharIndex) {\n return withWhere(leafInfo);\n }\n lastLeafInfo = leafInfo;\n }\n\n return withWhere(lastLeafInfo);\n }\n}\n\nexport class TwistyAlgEditorModel {\n valueProp = new TwistyAlgEditorValueProp();\n selectionProp = new TwistyAlgEditorSelectionProp();\n targetCharProp = new TargetCharProp({ selectionInfo: this.selectionProp });\n\n algEditorAlgWithIssues = new AlgEditorAlgWithIssuesProp({\n value: this.valueProp,\n });\n\n leafTokensProp = new LeafTokensProp({\n algWithIssues: this.algEditorAlgWithIssues,\n });\n\n leafToHighlight = new LeafToHighlightProp({\n leafTokens: this.leafTokensProp,\n targetChar: this.targetCharProp,\n });\n}\n", "import { CSSSource } from \"../ManagedCustomElement\";\n\nexport const twistyAlgEditorCSS = new CSSSource(`\n:host {\n width: 384px;\n display: grid;\n}\n\n.wrapper {\n /*overflow: hidden;\n resize: horizontal;*/\n\n background: var(--background, none);\n display: grid;\n}\n\ntextarea, .carbon-copy {\n grid-area: 1 / 1 / 2 / 2;\n\n width: 100%;\n font-family: sans-serif;\n line-height: 1.2em;\n\n font-size: var(--font-size, inherit);\n font-family: var(--font-family, sans-serif);\n\n box-sizing: border-box;\n\n padding: var(--padding, 0.5em);\n /* Prevent horizontal growth. */\n overflow-x: hidden;\n}\n\ntextarea {\n resize: none;\n background: none;\n z-index: 2;\n overflow: hidden;\n border: 1px solid var(--border-color, rgba(0, 0, 0, 0.25));\n}\n\n.carbon-copy {\n white-space: pre-wrap;\n word-wrap: break-word;\n color: transparent;\n user-select: none;\n pointer-events: none;\n\n z-index: 1;\n}\n\n.carbon-copy .highlight {\n background: var(--highlight-color, rgba(255, 128, 0, 0.5));\n padding: 0.1em 0.2em;\n margin: -0.1em -0.2em;\n border-radius: 0.2em;\n}\n\n.wrapper.issue-warning textarea,\n.wrapper.valid-for-puzzle-warning textarea {\n outline: none;\n border: 1px solid rgba(200, 200, 0, 0.5);\n background: rgba(255, 255, 0, 0.1);\n}\n\n.wrapper.issue-error textarea,\n.wrapper.valid-for-puzzle-error textarea {\n outline: none;\n border: 1px solid red;\n background: rgba(255, 0, 0, 0.1);\n}\n`);\n", "/**\n * Warning: the current implementation of <twisty-alg-editor> is *not good*,\n * but it is *good enough*. The important parts is that:\n *\n * - The editor can be used in apps without much effort.\n * - The editor handles alg validation and move highlighting *okay* when not\n * connected to a `<twisty-player>`.\n * - The editor stays in sync if it's connected to a `<twisty-player>`.\n *\n * The current implementation still has some race conditions and edge cases. A\n * proper rewrite with a better model would be very welcome.\n */\n\nimport type { ExperimentalParsed } from \"../../../alg\";\nimport { Alg, Move, Pause } from \"../../../alg\";\nimport type { Parsed } from \"../../../alg/parse\";\nimport type {\n AlgProp,\n AlgWithIssues,\n} from \"../../model/props/puzzle/state/AlgProp\";\nimport type { CurrentLeavesSimplified } from \"../../model/props/puzzle/state/CurrentLeavesSimplified\";\nimport { ClassListManager } from \"../ClassListManager\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { TwistyPlayer } from \"../TwistyPlayer\";\nimport { HighlightInfo, TwistyAlgEditorModel } from \"./model\";\nimport { twistyAlgEditorCSS } from \"./TwistyAlgEditor.css\";\n\nconst ATTRIBUTE_FOR_TWISTY_PLAYER = \"for-twisty-player\";\nconst ATTRIBUTE_PLACEHOLDER = \"placeholder\";\nconst ATTRIBUTE_TWISTY_PLAYER_PROP = \"twisty-player-prop\";\n\ntype TwistyPlayerAlgProp = \"alg\" | \"setupAlg\";\n\nexport class TwistyAlgEditor extends ManagedCustomElement {\n model = new TwistyAlgEditorModel();\n\n // #alg: Alg = new Alg();\n #textarea: HTMLTextAreaElement = document.createElement(\"textarea\");\n #carbonCopy: HTMLDivElement = document.createElement(\"div\");\n #carbonCopyPrefix: HTMLSpanElement = document.createElement(\"span\");\n #carbonCopyHighlight: HTMLSpanElement = document.createElement(\"span\");\n #carbonCopySuffix: HTMLSpanElement = document.createElement(\"span\");\n\n // #textareaClassListManager: ClassListManager<\"none\" | \"warning\" | \"error\"> =\n // new ClassListManager(this, \"issue-\", [\"none\", \"warning\", \"error\"]);\n\n #textareaClassListValidForPuzzleManager: ClassListManager<\n \"none\" | \"warning\" | \"error\"\n > = new ClassListManager(this, \"valid-for-puzzle-\", [\n \"none\",\n \"warning\",\n \"error\",\n ]);\n\n #twistyPlayer: TwistyPlayer | null = null;\n #twistyPlayerProp: TwistyPlayerAlgProp;\n get #algProp(): AlgProp | null {\n if (this.#twistyPlayer === null) {\n return null;\n } else {\n return this.#twistyPlayer.experimentalModel[this.#twistyPlayerProp];\n }\n }\n\n // Temporary Workaround for Twizzle Explorer\n debugNeverRequestTimestamp: boolean = false;\n\n constructor(options?: {\n twistyPlayer?: TwistyPlayer;\n twistyPlayerProp?: TwistyPlayerAlgProp;\n }) {\n super();\n this.#carbonCopy.classList.add(\"carbon-copy\");\n this.addElement(this.#carbonCopy);\n this.#textarea.rows = 1;\n this.addElement(this.#textarea);\n this.#carbonCopyPrefix.classList.add(\"prefix\");\n this.#carbonCopy.appendChild(this.#carbonCopyPrefix);\n this.#carbonCopyHighlight.classList.add(\"highlight\");\n this.#carbonCopy.appendChild(this.#carbonCopyHighlight);\n this.#carbonCopySuffix.classList.add(\"suffix\");\n this.#carbonCopy.appendChild(this.#carbonCopySuffix);\n\n this.#textarea.placeholder = \"Alg\";\n // Prevent iOS from defaulting to smart quotes.\n this.#textarea.setAttribute(\"spellcheck\", \"false\");\n\n this.addCSS(twistyAlgEditorCSS);\n\n // TODO: What set of events should we register? `change`? `keydown`?\n this.#textarea.addEventListener(\"input\", () => {\n this.#onInputHasFired = true;\n this.onInput();\n });\n this.#textarea.addEventListener(\"blur\", () => this.onBlur());\n document.addEventListener(\"selectionchange\", () =>\n this.onSelectionChange(),\n );\n\n if (options?.twistyPlayer) {\n this.twistyPlayer = options.twistyPlayer;\n }\n this.#twistyPlayerProp = options?.twistyPlayerProp ?? \"alg\";\n\n if (options?.twistyPlayerProp === \"alg\") {\n this.model.leafToHighlight.addFreshListener(\n (highlightInfo: HighlightInfo | null) => {\n if (highlightInfo) {\n this.highlightLeaf(highlightInfo.leafInfo.leaf);\n }\n },\n );\n }\n }\n\n // TODO\n set algString(s: string) {\n this.#textarea.value = s;\n this.onInput();\n }\n\n // TODO: remove?\n get algString(): string {\n return this.#textarea.value;\n }\n\n // To we need a getter?\n set placeholder(placeholderText: string) {\n this.#textarea.placeholder = placeholderText;\n }\n\n #onInputHasFired = false;\n onInput(): void {\n this.#carbonCopyHighlight.hidden = true;\n this.highlightLeaf(null);\n\n // TODO: This is a hack so that the you don't get a warning when the cursor\n // is after the space while typing `R U`. It would be nice to have something\n // cursor-aware that can also ignore whitespace warnings (or other syntax\n // errors due to normal input) adjacent to the cursor when it's in the\n // middle, but this is suffuciently useful for now.\n const endTrimmed = this.#textarea.value.trimEnd();\n this.model.valueProp.set(endTrimmed);\n this.#algProp?.set(endTrimmed);\n }\n\n async onSelectionChange(): Promise<void> {\n if (\n document.activeElement !== this ||\n this.shadow.activeElement !== this.#textarea\n ) {\n return;\n }\n if (this.#twistyPlayerProp !== \"alg\") {\n return;\n }\n\n const { selectionStart, selectionEnd } = this.#textarea;\n this.model.selectionProp.set({\n selectionStart,\n selectionEnd,\n });\n }\n\n async onBlur(): Promise<void> {\n // TODO: Figure out how not to make the cursor jump.\n // const parsed = Alg.fromString(this.algString);\n // this.algString = parsed.toString();\n // const [currentLeavesSimplified, indexer] = await Promise.all([\n // this.#twistyPlayer!.model.currentLeavesSimplifiedProp.get(),\n // this.#twistyPlayer!.model.indexerProp.get(),\n // ]);\n // const leaf = indexer.getAnimLeaf(currentLeavesSimplified.stateIndex);\n // this.highlightLeaf(leaf as Parsed<Move | Pause> | null);\n }\n\n setAlgIssueClassForPuzzle(issues: \"none\" | \"warning\" | \"error\") {\n this.#textareaClassListValidForPuzzleManager.setValue(issues);\n }\n\n // `white-space: pre;` mostly matches the formatting of the `<textarea>`, *except* when we end with a newline.\n // So we add an space to ensure that there is a character on the final line (that is very unlikely to trigger extra line wrapping).\n #padSuffix(s: string): string {\n return s.endsWith(\"\\n\") ? s + \" \" : s;\n }\n\n #highlightedLeaf: ExperimentalParsed<Move | Pause> | null = null;\n // TODO: support a primary highlighted move and secondary ones.\n highlightLeaf(leaf: ExperimentalParsed<Move | Pause> | null): void {\n if (this.#twistyPlayerProp !== \"alg\") {\n return;\n }\n if (leaf === null) {\n this.#carbonCopyPrefix.textContent = \"\";\n this.#carbonCopyHighlight.textContent = \"\";\n this.#carbonCopySuffix.textContent = this.#padSuffix(\n this.#textarea.value,\n );\n return;\n }\n if (leaf === this.#highlightedLeaf) {\n return;\n }\n this.#highlightedLeaf = leaf;\n this.#carbonCopyPrefix.textContent = this.#textarea.value.slice(\n 0,\n leaf.startCharIndex,\n );\n this.#carbonCopyHighlight.textContent = this.#textarea.value.slice(\n leaf.startCharIndex,\n leaf.endCharIndex,\n );\n this.#carbonCopySuffix.textContent = this.#padSuffix(\n this.#textarea.value.slice(leaf.endCharIndex),\n );\n this.#carbonCopyHighlight.hidden = false;\n }\n\n get twistyPlayer(): TwistyPlayer | null {\n return this.#twistyPlayer;\n }\n\n // TODO: spread out this impl over private methods instead of self-listeners.\n set twistyPlayer(twistyPlayer: TwistyPlayer | null) {\n if (this.#twistyPlayer) {\n // TODO: support reassigment/clearing\n console.warn(\"twisty-player reassignment/clearing is not supported\");\n return;\n }\n this.#twistyPlayer = twistyPlayer;\n if (!twistyPlayer) {\n return;\n }\n (async () => {\n this.algString = this.#algProp\n ? (await this.#algProp.get()).alg.toString()\n : \"\";\n })();\n\n if (this.#twistyPlayerProp === \"alg\") {\n // this.model.leafToHighlight.addFreshListener(\n // this.highlightLeaf.bind(this),\n // );\n\n // TODO: listen to puzzle prop?\n this.#twistyPlayer?.experimentalModel.puzzleAlg.addFreshListener(\n (algWithIssues: AlgWithIssues) => {\n // console.log(JSON.stringify(algWithIssues));\n if (algWithIssues.issues.errors.length === 0) {\n this.setAlgIssueClassForPuzzle(\n // TODO: Allow trailing spaces.\n algWithIssues.issues.warnings.length === 0 ? \"none\" : \"warning\",\n );\n const newAlg = algWithIssues.alg;\n const oldAlg = Alg.fromString(this.algString);\n if (!newAlg.isIdentical(oldAlg)) {\n this.algString = newAlg.toString();\n this.onInput();\n } else {\n // this.model.algInputProp.set(oldAlg);\n }\n } else {\n this.setAlgIssueClassForPuzzle(\"error\");\n }\n },\n );\n\n this.model.leafToHighlight.addFreshListener(\n async (highlightInfo: HighlightInfo | null) => {\n if (highlightInfo === null) {\n return;\n }\n // TODO: This indexer can be out of date!\n const [indexer, timestampRequest] = await Promise.all([\n await twistyPlayer.experimentalModel.indexer.get(),\n await twistyPlayer.experimentalModel.timestampRequest.get(),\n ]);\n if (\n timestampRequest === \"opposite-anchor\" &&\n !this.#onInputHasFired\n ) {\n return;\n }\n const moveStartTimestamp = indexer.indexToMoveStartTimestamp(\n highlightInfo.leafInfo.idx,\n );\n const duration = indexer.moveDuration(highlightInfo.leafInfo.idx);\n\n let newTimestamp: number;\n switch (highlightInfo.where) {\n case \"before\":\n newTimestamp = moveStartTimestamp;\n break;\n case \"start\":\n case \"inside\":\n newTimestamp = moveStartTimestamp + duration / 4;\n break;\n case \"end\":\n case \"after\":\n newTimestamp = moveStartTimestamp + duration;\n break;\n default:\n console.log(\"invalid where\");\n throw new Error(\"Invalid where!\");\n }\n if (!this.debugNeverRequestTimestamp) {\n twistyPlayer.experimentalModel.timestampRequest.set(newTimestamp);\n }\n },\n );\n\n twistyPlayer.experimentalModel.currentLeavesSimplified.addFreshListener(\n async (currentLeavesSimplified: CurrentLeavesSimplified) => {\n const indexer = await twistyPlayer.experimentalModel.indexer.get();\n const leaf = indexer.getAnimLeaf(currentLeavesSimplified.stateIndex);\n this.highlightLeaf(leaf as Parsed<Move | Pause> | null);\n },\n );\n }\n }\n\n protected attributeChangedCallback(\n attributeName: string,\n _oldValue: string,\n newValue: string,\n ): void {\n switch (attributeName) {\n case ATTRIBUTE_FOR_TWISTY_PLAYER: {\n const elem = document.getElementById(newValue);\n if (!elem) {\n console.warn(`${ATTRIBUTE_FOR_TWISTY_PLAYER}= elem does not exist`);\n return;\n }\n if (!(elem instanceof TwistyPlayer)) {\n // TODO: avoid assuming single instance of lib?\n console.warn(`${ATTRIBUTE_FOR_TWISTY_PLAYER}=is not a twisty-player`);\n return;\n }\n this.twistyPlayer = elem;\n return;\n }\n case ATTRIBUTE_PLACEHOLDER:\n this.placeholder = newValue;\n return;\n case ATTRIBUTE_TWISTY_PLAYER_PROP:\n if (this.#twistyPlayer) {\n console.log(\"cannot set prop\");\n throw new Error(\"cannot set prop after twisty player\");\n }\n this.#twistyPlayerProp = newValue as TwistyPlayerAlgProp;\n return;\n }\n }\n\n static get observedAttributes(): string[] {\n return [\n ATTRIBUTE_FOR_TWISTY_PLAYER,\n ATTRIBUTE_PLACEHOLDER,\n ATTRIBUTE_TWISTY_PLAYER_PROP,\n ];\n }\n}\n\ncustomElementsShim.define(\"twisty-alg-editor\", TwistyAlgEditor);\ndeclare global {\n interface HTMLElementTagNameMap {\n \"twisty-alg-editor\": TwistyAlgEditor;\n }\n}\n", "import { CSSSource } from \"../ManagedCustomElement\";\n\nexport const twizzleLinkCSS = new CSSSource(`\n.wrapper {\n background: rgb(255, 245, 235);\n display: grid;\n grid-template-columns: 1fr;\n border: 1px solid rgba(0, 0, 0, 0.25);\n}\n\n.setup-alg, twisty-alg-viewer {\n padding: 0.5em 1em;\n}\n\n.heading {\n background: rgba(255, 230, 210, 1);\n font-weight: bold;\n padding: 0.25em 0.5em;\n}\n\n.heading.title {\n background: rgb(255, 245, 235);\n font-size: 150%;\n white-space: pre;\n}\n\ntwisty-player {\n width: 100%;\n resize: vertical;\n overflow-y: hidden;\n}\n\ntwisty-player + .heading {\n padding-top: 0.5em;\n}\n`);\n", "import { EXPERIMENTAL_PROP_NO_VALUE } from \"../../../../cubing/twisty\";\nimport type {\n AlgProp,\n AlgWithIssues,\n} from \"../../../../cubing/twisty/model/props/puzzle/state/AlgProp\";\nimport type { TwistyPlayerModel } from \"../../../../cubing/twisty/model/TwistyPlayerModel\";\nimport type { TwistyPropSource } from \"../../../../cubing/twisty/model/props/TwistyProp\";\nimport {\n TwistyPlayerAttribute,\n twistyPlayerAttributeMap,\n TwistyPlayerConfig,\n} from \"../../../../cubing/twisty/views/TwistyPlayer\";\n\nfunction updateURL(url: URL): void {\n window.history.replaceState(\"\", \"\", url.toString());\n}\n\n// TODO: Find a way to connect this to the `TwistyPlayer` constructor?\n\nexport type URLParamUpdaterOptions = {\n prefix?: string;\n};\n\nexport class URLParamUpdater {\n #prefix: string;\n constructor(model: TwistyPlayerModel, options?: URLParamUpdaterOptions) {\n this.#prefix = options?.prefix ?? \"\";\n\n this.listenToAlgProp(model.alg, \"alg\");\n this.listenToAlgProp(model.setupAlg, \"setup-alg\");\n this.listenToStringSourceProp(\n model.twistySceneModel.stickering,\n \"stickering\",\n );\n this.listenToStringSourceProp(model.setupAnchor, \"setup-anchor\");\n this.listenToStringOrNullProp(model.title, \"title\");\n this.listenToStringOrNoValueProp(\n model.puzzleIDRequest,\n \"puzzle\",\n EXPERIMENTAL_PROP_NO_VALUE,\n );\n this.listenToStringOrNoValueProp(\n model.puzzleDescriptionRequest,\n \"puzzle-description\",\n EXPERIMENTAL_PROP_NO_VALUE,\n );\n }\n\n // TODO: Cache parsed URL?\n setURLParam(\n unprefixedKey: string,\n value: string,\n defaultString: string,\n ): void {\n const prefixedKey = this.#prefix + unprefixedKey;\n const url = new URL(location.href);\n if (value === defaultString) {\n url.searchParams.delete(prefixedKey);\n } else {\n url.searchParams.set(prefixedKey, value);\n }\n updateURL(url);\n }\n\n async listenToStringSourceProp(\n prop: TwistyPropSource<string>,\n key: string,\n defaultString?: string,\n ): Promise<void> {\n const actualDefaultString = defaultString ?? (await prop.getDefaultValue());\n prop.addFreshListener((s: string) => {\n this.setURLParam(key, s, actualDefaultString);\n });\n }\n\n async listenToStringOrNullProp(\n prop: TwistyPropSource<string | null>,\n key: string,\n defaultString: string = \"\",\n ): Promise<void> {\n prop.addFreshListener((s: string | null) => {\n this.setURLParam(key, s ?? defaultString, defaultString);\n });\n }\n\n async listenToStringOrNoValueProp(\n prop: TwistyPropSource<string | typeof EXPERIMENTAL_PROP_NO_VALUE>,\n key: string,\n defaultString: string | typeof EXPERIMENTAL_PROP_NO_VALUE,\n ): Promise<void> {\n prop.addFreshListener((s: string | typeof EXPERIMENTAL_PROP_NO_VALUE) => {\n if (s === EXPERIMENTAL_PROP_NO_VALUE) {\n s = defaultString;\n }\n if (s === EXPERIMENTAL_PROP_NO_VALUE) {\n this.setURLParam(key, \"\", \"\");\n } else {\n this.setURLParam(key, s, \"\"); // TODO\n }\n });\n }\n\n listenToAlgProp(prop: AlgProp, key: string): void {\n prop.addFreshListener((algWithIssues: AlgWithIssues) => {\n this.setURLParam(key, algWithIssues.alg.toString(), \"\");\n });\n }\n}\n\nexport function getConfigFromURL(\n prefix = \"\",\n url: string = location.href,\n): TwistyPlayerConfig {\n // TODO: Why does `Object.entries(paramMapping)` crash if this is defined elswhere?\n const paramMapping: Record<string, TwistyPlayerAttribute> = {\n \"alg\": \"alg\",\n \"setup-alg\": \"experimental-setup-alg\",\n \"setup-anchor\": \"experimental-setup-anchor\",\n \"puzzle\": \"puzzle\",\n \"stickering\": \"experimental-stickering\",\n \"puzzle-description\": \"experimental-puzzle-description\",\n \"title\": \"experimental-title\",\n \"video-url\": \"experimental-video-url\",\n \"competition\": \"experimental-competition-id\",\n };\n\n const params = new URL(url).searchParams;\n const config: TwistyPlayerConfig = {};\n for (const [ourParam, twistyPlayerParam] of Object.entries(paramMapping)) {\n const paramValue = params.get(prefix + ourParam);\n if (paramValue !== null) {\n // TODO: type\n const configKey = twistyPlayerAttributeMap[twistyPlayerParam];\n (config as any)[configKey] = paramValue;\n }\n }\n return config;\n}\n\nexport function remapLegacyURLParams(\n mapping: Record<string, string | null>,\n): void {\n const url = new URL(location.href);\n for (const [oldKey, newKey] of Object.entries(mapping)) {\n // `null` indicates there is no new key, i.e. just drop the old key\n if (newKey !== null) {\n // The new key takes precedents, so we only remap the old key if the new key\n // is not already set.\n if (!url.searchParams.has(newKey)) {\n const value = url.searchParams.get(oldKey);\n if (value !== null) {\n url.searchParams.set(newKey, value);\n }\n }\n }\n url.searchParams.delete(oldKey);\n }\n updateURL(url);\n}\n", "import { TwistyPlayer } from \"../..\";\nimport { Alg } from \"../../../alg\";\nimport { puzzles } from \"../../../puzzles\";\nimport { ManagedCustomElement } from \"../ManagedCustomElement\";\nimport { customElementsShim } from \"../node-custom-element-shims\";\nimport { TwistyAlgViewer } from \"../TwistyAlgViewer\";\nimport { twizzleLinkCSS } from \"./TwizzleLink.css\";\nimport { getConfigFromURL } from \"./url-params\";\n\nexport class TwizzleLink extends ManagedCustomElement {\n twistyPlayer: TwistyPlayer | null = null;\n a: HTMLAnchorElement | null = null;\n constructor() {\n super({ mode: \"open\" });\n }\n\n fallback() {\n this.contentWrapper.textContent = \"\";\n if (this.a) {\n const span = this.contentWrapper.appendChild(\n document.createElement(\"span\"),\n );\n span.textContent = \"\u2757\uFE0F\";\n span.title = \"Could not show a player for link\";\n this.addElement(this.a);\n }\n if (this.#cssElem) {\n this.#cssElem.remove();\n }\n }\n\n #cssElem: HTMLStyleElement | undefined;\n async connectedCallback() {\n this.#cssElem = this.addCSS(twizzleLinkCSS);\n this.a = this.querySelector(\"a\");\n if (!this.a) {\n return;\n }\n\n const config = getConfigFromURL(\"\", this.a.href);\n\n const href = this.a?.href;\n const { hostname, pathname } = new URL(href);\n\n if (hostname !== \"alpha.twizzle.net\") {\n this.fallback();\n return;\n }\n if ([\"/edit/\", \"/explore/\"].includes(pathname)) {\n const isExplorer = pathname === \"/explore/\";\n\n if (config.puzzle && !(config.puzzle in puzzles)) {\n const puzzleDescription = (\n await import(\"../../../puzzle-geometry\")\n ).getPuzzleDescriptionString(config.puzzle);\n delete config.puzzle;\n config.experimentalPuzzleDescription = puzzleDescription;\n }\n\n this.twistyPlayer = this.addElement(\n new TwistyPlayer({\n ...config,\n viewerLink: isExplorer ? \"experimental-twizzle-explorer\" : \"auto\",\n }),\n );\n\n if (config.experimentalTitle) {\n this.addHeading(config.experimentalTitle).classList.add(\"title\");\n // const setupAlgDiv = this.addElement(document.createElement(\"div\"));\n // setupAlgDiv.classList.add(\"setup-alg\");\n // setupAlgDiv.textContent = puzzles[config.puzzle ?? \"3x3x3\"].fullName;\n }\n\n if (config.experimentalSetupAlg) {\n this.addHeading(\"Setup\");\n\n const setupAlgDiv = this.addElement(document.createElement(\"div\"));\n setupAlgDiv.classList.add(\"setup-alg\");\n setupAlgDiv.textContent = new Alg(\n config.experimentalSetupAlg,\n ).toString();\n }\n this.addHeading(\"Moves\");\n const twistyAlgViewer = this.addElement(\n new TwistyAlgViewer({ twistyPlayer: this.twistyPlayer }),\n );\n twistyAlgViewer.part.add(\"twisty-alg-viewer\");\n } else {\n this.fallback();\n }\n }\n\n addHeading(text: string): HTMLElement {\n const headingDiv = this.addElement(document.createElement(\"div\"));\n headingDiv.classList.add(\"heading\");\n headingDiv.textContent = text;\n return headingDiv;\n }\n}\n\ncustomElementsShim.define(\"twizzle-link\", TwizzleLink);\ndeclare global {\n interface HTMLElementTagNameMap {\n \"twizzle-link\": TwizzleLink;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|