cubing 0.29.2 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/dist/esm/alg/index.js +1 -2
  2. package/dist/esm/bluetooth/index.js +8 -9
  3. package/dist/esm/bluetooth/index.js.map +2 -2
  4. package/dist/esm/{chunk-RH4WZIGC.js → chunk-5QXVR3FK.js} +2 -2
  5. package/dist/esm/{chunk-RH4WZIGC.js.map → chunk-5QXVR3FK.js.map} +0 -0
  6. package/dist/esm/{chunk-WNZXZ4MW.js → chunk-7LJHXZJM.js} +6 -8
  7. package/dist/esm/{chunk-WNZXZ4MW.js.map → chunk-7LJHXZJM.js.map} +2 -2
  8. package/dist/esm/{chunk-OT7AIIFN.js → chunk-CUIME76I.js} +3 -3
  9. package/dist/esm/chunk-CUIME76I.js.map +7 -0
  10. package/dist/esm/{chunk-NUMCMGLU.js → chunk-J5IQUWXC.js} +2 -2
  11. package/dist/esm/{chunk-NUMCMGLU.js.map → chunk-J5IQUWXC.js.map} +0 -0
  12. package/dist/esm/{chunk-J5KJ2WWA.js → chunk-JQLCWEVU.js} +44 -31
  13. package/dist/esm/chunk-JQLCWEVU.js.map +7 -0
  14. package/dist/esm/{chunk-7OIUETFU.js → chunk-RBZINRTT.js} +213 -106
  15. package/dist/esm/chunk-RBZINRTT.js.map +7 -0
  16. package/dist/esm/{chunk-EOEJDDXN.js → chunk-SNLVO6OQ.js} +256 -31
  17. package/dist/esm/chunk-SNLVO6OQ.js.map +7 -0
  18. package/dist/esm/{chunk-YD2TMJI2.js → chunk-SYSXHJ4V.js} +137 -183
  19. package/dist/esm/chunk-SYSXHJ4V.js.map +7 -0
  20. package/dist/esm/{chunk-POCUG6QW.js → chunk-UAHLC2BK.js} +3 -5
  21. package/dist/esm/{chunk-POCUG6QW.js.map → chunk-UAHLC2BK.js.map} +2 -2
  22. package/dist/esm/{chunk-RIXFKOD6.js → chunk-V67YQOIN.js} +4 -4
  23. package/dist/esm/{chunk-RIXFKOD6.js.map → chunk-V67YQOIN.js.map} +2 -2
  24. package/dist/esm/kpuzzle/index.js +2 -3
  25. package/dist/esm/notation/index.js +2 -3
  26. package/dist/esm/protocol/index.js +4 -5
  27. package/dist/esm/puzzle-geometry/index.js +6 -19
  28. package/dist/esm/puzzle-geometry/index.js.map +2 -2
  29. package/dist/esm/puzzles/index.js +4 -5
  30. package/dist/esm/{puzzles-dynamic-3x3x3-KIG5A6QR.js → puzzles-dynamic-3x3x3-ZKMODX2P.js} +1 -3
  31. package/dist/esm/{puzzles-dynamic-3x3x3-KIG5A6QR.js.map → puzzles-dynamic-3x3x3-ZKMODX2P.js.map} +1 -1
  32. package/dist/esm/{puzzles-dynamic-4x4x4-PEDAPUZK.js → puzzles-dynamic-4x4x4-DT42HVIY.js} +1 -3
  33. package/dist/esm/{puzzles-dynamic-4x4x4-PEDAPUZK.js.map → puzzles-dynamic-4x4x4-DT42HVIY.js.map} +1 -1
  34. package/dist/esm/{puzzles-dynamic-side-events-3K26JTOG.js → puzzles-dynamic-side-events-HMUBMHA5.js} +1 -3
  35. package/dist/esm/{puzzles-dynamic-side-events-3K26JTOG.js.map → puzzles-dynamic-side-events-HMUBMHA5.js.map} +1 -1
  36. package/dist/esm/{puzzles-dynamic-unofficial-WWJ4NJMX.js → puzzles-dynamic-unofficial-QXSDLTK5.js} +1 -3
  37. package/dist/esm/{puzzles-dynamic-unofficial-WWJ4NJMX.js.map → puzzles-dynamic-unofficial-QXSDLTK5.js.map} +1 -1
  38. package/dist/esm/scramble/index.js +2 -3
  39. package/dist/esm/search/index.js +6 -7
  40. package/dist/esm/{search-dynamic-sgs-side-events-AE3TLLPA.js → search-dynamic-sgs-side-events-KVUAIBGE.js} +6 -7
  41. package/dist/esm/{search-dynamic-sgs-side-events-AE3TLLPA.js.map → search-dynamic-sgs-side-events-KVUAIBGE.js.map} +1 -1
  42. package/dist/esm/{search-dynamic-sgs-unofficial-JUXMNMNO.js → search-dynamic-sgs-unofficial-7ICOL4T7.js} +6 -7
  43. package/dist/esm/{search-dynamic-sgs-unofficial-JUXMNMNO.js.map → search-dynamic-sgs-unofficial-7ICOL4T7.js.map} +1 -1
  44. package/dist/esm/{search-dynamic-solve-3x3x3-SA75BI5I.js → search-dynamic-solve-3x3x3-DDVSUP2C.js} +275 -292
  45. package/dist/esm/search-dynamic-solve-3x3x3-DDVSUP2C.js.map +7 -0
  46. package/dist/esm/{search-dynamic-solve-4x4x4-ALKH43DT.js → search-dynamic-solve-4x4x4-GGDX7YYZ.js} +6 -7
  47. package/dist/esm/{search-dynamic-solve-4x4x4-ALKH43DT.js.map → search-dynamic-solve-4x4x4-GGDX7YYZ.js.map} +1 -1
  48. package/dist/esm/{search-dynamic-solve-fto-5B5ZESQC.js → search-dynamic-solve-fto-MA4X6JEE.js} +6 -17
  49. package/dist/esm/search-dynamic-solve-fto-MA4X6JEE.js.map +7 -0
  50. package/dist/esm/{search-dynamic-solve-kilominx-OY4VIARG.js → search-dynamic-solve-kilominx-TVKK4KDH.js} +2 -3
  51. package/dist/esm/search-dynamic-solve-kilominx-TVKK4KDH.js.map +7 -0
  52. package/dist/esm/{search-dynamic-solve-master_tetraminx-GE2BTRGI.js → search-dynamic-solve-master_tetraminx-YKINTRUU.js} +4 -11
  53. package/dist/esm/search-dynamic-solve-master_tetraminx-YKINTRUU.js.map +7 -0
  54. package/dist/esm/{search-dynamic-solve-sq1-W6PSSLR6.js → search-dynamic-solve-sq1-W33UXTDZ.js} +1 -2
  55. package/dist/esm/{search-dynamic-solve-sq1-W6PSSLR6.js.map → search-dynamic-solve-sq1-W33UXTDZ.js.map} +1 -1
  56. package/dist/esm/{search-worker-inside-generated-string-7HYFSSPW.js → search-worker-inside-generated-string-I4T4KADX.js} +28 -30
  57. package/dist/esm/search-worker-inside-generated-string-I4T4KADX.js.map +7 -0
  58. package/dist/esm/{search-worker-js-entry-SNUA3SOE.js → search-worker-js-entry-KWGCJXGS.js} +34 -41
  59. package/dist/esm/search-worker-js-entry-KWGCJXGS.js.map +7 -0
  60. package/dist/esm/{search-worker-ts-entry-LNB7KNFY.js → search-worker-ts-entry-J533AM5E.js} +2 -3
  61. package/dist/esm/{search-worker-ts-entry-LNB7KNFY.js.map → search-worker-ts-entry-J533AM5E.js.map} +1 -1
  62. package/dist/esm/stream/index.js +1 -2
  63. package/dist/esm/stream/index.js.map +2 -2
  64. package/dist/esm/twisty/index.js +450 -254
  65. package/dist/esm/twisty/index.js.map +4 -4
  66. package/dist/esm/{twisty-dynamic-3d-PU74EKRA.js → twisty-dynamic-3d-OAYMJ6OD.js} +125 -107
  67. package/dist/esm/twisty-dynamic-3d-OAYMJ6OD.js.map +7 -0
  68. package/dist/types/{Alg-137fb0d5.d.ts → Alg-60b374e8.d.ts} +25 -26
  69. package/dist/types/{KState-a73111d7.d.ts → KState-958b873c.d.ts} +1 -1
  70. package/dist/types/{TwizzleLink-ce20e840.d.ts → TwizzleLink-e873f6e5.d.ts} +77 -54
  71. package/dist/types/alg/index.d.ts +31 -9
  72. package/dist/types/bluetooth/index.d.ts +4 -4
  73. package/dist/types/{bluetooth-puzzle-8a678993.d.ts → bluetooth-puzzle-cc8eeaae.d.ts} +2 -2
  74. package/dist/types/kpuzzle/index.d.ts +2 -2
  75. package/dist/types/notation/index.d.ts +1 -1
  76. package/dist/types/{outside-e55f28a0.d.ts → outside-15f39b79.d.ts} +2 -2
  77. package/dist/types/{parseAlg-a28f7568.d.ts → parseAlg-3c77c4b3.d.ts} +1 -1
  78. package/dist/types/protocol/index.d.ts +2 -2
  79. package/dist/types/puzzle-geometry/index.d.ts +3 -3
  80. package/dist/types/puzzles/index.d.ts +5 -5
  81. package/dist/types/scramble/index.d.ts +3 -3
  82. package/dist/types/search/index.d.ts +3 -3
  83. package/dist/types/stream/index.d.ts +3 -3
  84. package/dist/types/twisty/index.d.ts +6 -6
  85. package/package.json +3 -2
  86. package/dist/esm/chunk-7OIUETFU.js.map +0 -7
  87. package/dist/esm/chunk-EOEJDDXN.js.map +0 -7
  88. package/dist/esm/chunk-J5KJ2WWA.js.map +0 -7
  89. package/dist/esm/chunk-OT7AIIFN.js.map +0 -7
  90. package/dist/esm/chunk-SBZRVSPK.js +0 -30
  91. package/dist/esm/chunk-SBZRVSPK.js.map +0 -7
  92. package/dist/esm/chunk-YD2TMJI2.js.map +0 -7
  93. package/dist/esm/search-dynamic-solve-3x3x3-SA75BI5I.js.map +0 -7
  94. package/dist/esm/search-dynamic-solve-fto-5B5ZESQC.js.map +0 -7
  95. package/dist/esm/search-dynamic-solve-kilominx-OY4VIARG.js.map +0 -7
  96. package/dist/esm/search-dynamic-solve-master_tetraminx-GE2BTRGI.js.map +0 -7
  97. package/dist/esm/search-worker-inside-generated-string-7HYFSSPW.js.map +0 -7
  98. package/dist/esm/search-worker-js-entry-SNUA3SOE.js.map +0 -7
  99. package/dist/esm/twisty-dynamic-3d-PU74EKRA.js.map +0 -7
@@ -15,22 +15,24 @@ import {
15
15
  TwistyPropSource,
16
16
  customElementsShim,
17
17
  proxy3D,
18
+ rawRenderPooled,
18
19
  setCameraFromOrbitCoordinates,
19
20
  setTwistyDebug
20
- } from "../chunk-J5KJ2WWA.js";
21
+ } from "../chunk-JQLCWEVU.js";
21
22
  import "../chunk-QHWK5RXN.js";
22
23
  import {
23
24
  countAnimatedLeaves,
24
25
  countMoves
25
- } from "../chunk-NUMCMGLU.js";
26
+ } from "../chunk-J5IQUWXC.js";
26
27
  import {
27
28
  cube3x3x3,
28
29
  puzzles
29
- } from "../chunk-EOEJDDXN.js";
30
+ } from "../chunk-SNLVO6OQ.js";
30
31
  import {
31
- customPGPuzzleLoader
32
- } from "../chunk-YD2TMJI2.js";
33
- import "../chunk-POCUG6QW.js";
32
+ customPGPuzzleLoader,
33
+ getPieceStickeringMask
34
+ } from "../chunk-SYSXHJ4V.js";
35
+ import "../chunk-UAHLC2BK.js";
34
36
  import {
35
37
  Alg,
36
38
  AlgBuilder,
@@ -43,8 +45,7 @@ import {
43
45
  direct,
44
46
  directedGenerator,
45
47
  experimentalAppendMove
46
- } from "../chunk-7OIUETFU.js";
47
- import "../chunk-SBZRVSPK.js";
48
+ } from "../chunk-RBZINRTT.js";
48
49
 
49
50
  // src/cubing/twisty/controllers/AnimationTypes.ts
50
51
  function directionScalar(direction) {
@@ -380,42 +381,6 @@ var twistyViewerWrapperCSS = new CSSSource(
380
381
  `
381
382
  );
382
383
 
383
- // src/cubing/twisty/views/2D/Twisty2DPuzzle.css.ts
384
- var twisty2DSVGCSS = new CSSSource(
385
- `
386
- :host {
387
- width: 384px;
388
- height: 256px;
389
- display: grid;
390
- }
391
-
392
- .wrapper {
393
- width: 100%;
394
- height: 100%;
395
- display: grid;
396
- overflow: hidden;
397
- }
398
-
399
- .svg-wrapper,
400
- twisty-2d-svg,
401
- svg {
402
- width: 100%;
403
- height: 100%;
404
- display: grid;
405
- min-height: 0;
406
- }
407
-
408
- svg {
409
- animation: fade-in 0.25s ease-in;
410
- }
411
-
412
- @keyframes fade-in {
413
- from { opacity: 0; }
414
- to { opacity: 1; }
415
- }
416
- `
417
- );
418
-
419
384
  // src/cubing/twisty/views/2D/KPuzzleSVGWrapper.ts
420
385
  var xmlns = "http://www.w3.org/2000/svg";
421
386
  var svgCounter = 0;
@@ -458,7 +423,7 @@ var colorMaps = {
458
423
  }
459
424
  };
460
425
  var KPuzzleSVGWrapper = class {
461
- constructor(kpuzzle, svgSource, experimentalAppearance) {
426
+ constructor(kpuzzle, svgSource, experimentalStickeringMask) {
462
427
  this.kpuzzle = kpuzzle;
463
428
  this.originalColors = {};
464
429
  this.gradients = {};
@@ -488,26 +453,26 @@ var KPuzzleSVGWrapper = class {
488
453
  const id = this.elementID(orbitName, idx, orientation);
489
454
  const elem = this.elementByID(id);
490
455
  let originalColor = elem.style.fill;
491
- if (experimentalAppearance) {
456
+ if (experimentalStickeringMask) {
492
457
  (() => {
493
- const a = experimentalAppearance.orbits;
458
+ const a = experimentalStickeringMask.orbits;
494
459
  if (!a) {
495
460
  return;
496
461
  }
497
- const orbitAppearance = a[orbitName];
498
- if (!orbitAppearance) {
462
+ const orbitStickeringMask = a[orbitName];
463
+ if (!orbitStickeringMask) {
499
464
  return;
500
465
  }
501
- const pieceAppearance = orbitAppearance.pieces[idx];
502
- if (!pieceAppearance) {
466
+ const pieceStickeringMask = orbitStickeringMask.pieces[idx];
467
+ if (!pieceStickeringMask) {
503
468
  return;
504
469
  }
505
- const faceletAppearance = pieceAppearance.facelets[orientation];
506
- if (!faceletAppearance) {
470
+ const faceletStickeringMasks = pieceStickeringMask.facelets[orientation];
471
+ if (!faceletStickeringMasks) {
507
472
  return;
508
473
  }
509
- const appearance = typeof faceletAppearance === "string" ? faceletAppearance : faceletAppearance?.appearance;
510
- const colorMap = colorMaps[appearance];
474
+ const stickeringMask = typeof faceletStickeringMasks === "string" ? faceletStickeringMasks : faceletStickeringMasks?.mask;
475
+ const colorMap = colorMaps[stickeringMask];
511
476
  if (colorMap) {
512
477
  originalColor = colorMap[originalColor];
513
478
  }
@@ -641,6 +606,42 @@ var KPuzzleSVGWrapper = class {
641
606
  }
642
607
  };
643
608
 
609
+ // src/cubing/twisty/views/2D/Twisty2DPuzzle.css.ts
610
+ var twisty2DSVGCSS = new CSSSource(
611
+ `
612
+ :host {
613
+ width: 384px;
614
+ height: 256px;
615
+ display: grid;
616
+ }
617
+
618
+ .wrapper {
619
+ width: 100%;
620
+ height: 100%;
621
+ display: grid;
622
+ overflow: hidden;
623
+ }
624
+
625
+ .svg-wrapper,
626
+ twisty-2d-svg,
627
+ svg {
628
+ width: 100%;
629
+ height: 100%;
630
+ display: grid;
631
+ min-height: 0;
632
+ }
633
+
634
+ svg {
635
+ animation: fade-in 0.25s ease-in;
636
+ }
637
+
638
+ @keyframes fade-in {
639
+ from { opacity: 0; }
640
+ to { opacity: 1; }
641
+ }
642
+ `
643
+ );
644
+
644
645
  // src/cubing/twisty/views/2D/Twisty2DPuzzle.ts
645
646
  var Twisty2DPuzzle = class extends ManagedCustomElement {
646
647
  constructor(model, kpuzzle, svgSource, options, puzzleLoader) {
@@ -655,17 +656,22 @@ var Twisty2DPuzzle = class extends ManagedCustomElement {
655
656
  this.#freshListenerManager = new FreshListenerManager();
656
657
  this.addCSS(twisty2DSVGCSS);
657
658
  this.resetSVG();
658
- this.#freshListenerManager.addListener(this.model.puzzleID, (puzzleID) => {
659
- if (puzzleLoader?.id !== puzzleID) {
660
- this.disconnect();
659
+ this.#freshListenerManager.addListener(
660
+ this.model.puzzleID,
661
+ (puzzleID) => {
662
+ if (puzzleLoader?.id !== puzzleID) {
663
+ this.disconnect();
664
+ }
661
665
  }
662
- });
666
+ );
663
667
  this.#freshListenerManager.addListener(
664
668
  this.model.legacyPosition,
665
669
  this.onPositionChange.bind(this)
666
670
  );
667
- if (this.options?.experimentalStickering) {
668
- this.experimentalSetStickering(this.options.experimentalStickering);
671
+ if (this.options?.experimentalStickeringMask) {
672
+ this.experimentalSetStickeringMask(
673
+ this.options.experimentalStickeringMask
674
+ );
669
675
  }
670
676
  }
671
677
  #cachedPosition;
@@ -703,16 +709,10 @@ var Twisty2DPuzzle = class extends ManagedCustomElement {
703
709
  scheduleRender() {
704
710
  this.scheduler.requestAnimFrame();
705
711
  }
706
- experimentalSetStickering(stickering) {
707
- (async () => {
708
- if (!this.puzzleLoader?.appearance) {
709
- return;
710
- }
711
- const appearance = await this.puzzleLoader.appearance(stickering);
712
- this.resetSVG(appearance);
713
- })();
712
+ experimentalSetStickeringMask(stickeringMask) {
713
+ this.resetSVG(stickeringMask);
714
714
  }
715
- resetSVG(appearance) {
715
+ resetSVG(stickeringMask) {
716
716
  if (this.svgWrapper) {
717
717
  this.removeElement(this.svgWrapper.wrapperElement);
718
718
  }
@@ -722,7 +722,7 @@ var Twisty2DPuzzle = class extends ManagedCustomElement {
722
722
  this.svgWrapper = new KPuzzleSVGWrapper(
723
723
  this.kpuzzle,
724
724
  this.svgSource,
725
- appearance
725
+ stickeringMask
726
726
  );
727
727
  this.addElement(this.svgWrapper.wrapperElement);
728
728
  if (this.#cachedPosition) {
@@ -742,9 +742,14 @@ var Twisty2DPuzzleWrapper = class {
742
742
  this.puzzleLoader = puzzleLoader;
743
743
  this.effectiveVisualization = effectiveVisualization;
744
744
  this.twisty2DPuzzle();
745
- this.#freshListenerManager.addListener(this.model.twistySceneModel.stickering, async (stickering) => {
746
- (await this.twisty2DPuzzle()).experimentalSetStickering(stickering);
747
- });
745
+ this.#freshListenerManager.addListener(
746
+ this.model.twistySceneModel.stickeringMask,
747
+ async (stickeringMask) => {
748
+ (await this.twisty2DPuzzle()).experimentalSetStickeringMask(
749
+ stickeringMask
750
+ );
751
+ }
752
+ );
748
753
  }
749
754
  #freshListenerManager = new FreshListenerManager();
750
755
  disconnect() {
@@ -871,56 +876,61 @@ var Twisty3DPuzzleWrapper = class extends EventTarget {
871
876
  this.puzzleLoader = puzzleLoader;
872
877
  this.visualizationStrategy = visualizationStrategy;
873
878
  this.twisty3DPuzzle();
874
- this.#freshListenerManager.addListener(this.model.puzzleLoader, (puzzleLoader2) => {
875
- if (this.puzzleLoader.id !== puzzleLoader2.id) {
876
- this.disconnect();
879
+ this.#freshListenerManager.addListener(
880
+ this.model.puzzleLoader,
881
+ (puzzleLoader2) => {
882
+ if (this.puzzleLoader.id !== puzzleLoader2.id) {
883
+ this.disconnect();
884
+ }
877
885
  }
878
- });
879
- this.#freshListenerManager.addListener(this.model.legacyPosition, async (position) => {
880
- try {
881
- (await this.twisty3DPuzzle()).onPositionChange(position);
886
+ );
887
+ this.#freshListenerManager.addListener(
888
+ this.model.legacyPosition,
889
+ async (position) => {
890
+ try {
891
+ (await this.twisty3DPuzzle()).onPositionChange(position);
892
+ this.scheduleRender();
893
+ } catch (e) {
894
+ this.disconnect();
895
+ }
896
+ }
897
+ );
898
+ this.#freshListenerManager.addListener(
899
+ this.model.twistySceneModel.hintFacelet,
900
+ async (hintFaceletStyle) => {
901
+ (await this.twisty3DPuzzle()).experimentalUpdateOptions({
902
+ hintFacelets: hintFaceletStyle === "auto" ? "floating" : hintFaceletStyle
903
+ });
882
904
  this.scheduleRender();
883
- } catch (e) {
884
- this.disconnect();
885
905
  }
886
- });
887
- this.#freshListenerManager.addListener(this.model.twistySceneModel.hintFacelet, async (hintFaceletStyle) => {
888
- (await this.twisty3DPuzzle()).experimentalUpdateOptions({
889
- hintFacelets: hintFaceletStyle === "auto" ? "floating" : hintFaceletStyle
890
- });
891
- this.scheduleRender();
892
- });
893
- this.#freshListenerManager.addListener(this.model.twistySceneModel.foundationDisplay, async (foundationDisplay) => {
894
- (await this.twisty3DPuzzle()).experimentalUpdateOptions({
895
- showFoundation: foundationDisplay !== "none"
896
- });
897
- this.scheduleRender();
898
- });
899
- this.#freshListenerManager.addListener(this.model.twistySceneModel.stickering, async (stickering) => {
900
- if ("setStickering" in await this.twisty3DPuzzle()) {
901
- (await this.twisty3DPuzzle()).setStickering(stickering);
906
+ );
907
+ this.#freshListenerManager.addListener(
908
+ this.model.twistySceneModel.foundationDisplay,
909
+ async (foundationDisplay) => {
910
+ (await this.twisty3DPuzzle()).experimentalUpdateOptions({
911
+ showFoundation: foundationDisplay !== "none"
912
+ });
902
913
  this.scheduleRender();
903
- } else {
904
- if ("appearance" in this.puzzleLoader) {
905
- const [twisty3D, appearancePromise] = await Promise.all([
906
- this.twisty3DPuzzle(),
907
- this.puzzleLoader.appearance(stickering ?? "full")
908
- ]);
909
- twisty3D.experimentalSetAppearance(appearancePromise);
910
- this.scheduleRender();
911
- }
912
914
  }
913
- });
915
+ );
916
+ this.#freshListenerManager.addListener(
917
+ this.model.twistySceneModel.stickeringMask,
918
+ async (stickeringMask) => {
919
+ const twisty3D = await this.twisty3DPuzzle();
920
+ twisty3D.setStickeringMask(stickeringMask);
921
+ this.scheduleRender();
922
+ }
923
+ );
914
924
  this.#freshListenerManager.addMultiListener3(
915
925
  [
916
- this.model.twistySceneModel.stickering,
926
+ this.model.twistySceneModel.stickeringMask,
917
927
  this.model.twistySceneModel.foundationStickerSprite,
918
928
  this.model.twistySceneModel.hintStickerSprite
919
929
  ],
920
930
  async (inputs) => {
921
931
  if ("experimentalUpdateTexture" in await this.twisty3DPuzzle()) {
922
932
  (await this.twisty3DPuzzle()).experimentalUpdateTexture(
923
- inputs[0] === "picture",
933
+ inputs[0].specialBehaviour === "picture",
924
934
  inputs[1],
925
935
  inputs[2]
926
936
  );
@@ -942,16 +952,19 @@ var Twisty3DPuzzleWrapper = class extends EventTarget {
942
952
  return this.#cachedTwisty3DPuzzle ?? (this.#cachedTwisty3DPuzzle = (async () => {
943
953
  const proxyPromise = proxy3D();
944
954
  if (this.puzzleLoader.id === "3x3x3" && this.visualizationStrategy === "Cube3D") {
945
- const [foundationSprite, hintSprite, experimentalStickering] = await Promise.all([
955
+ const [foundationSprite, hintSprite, experimentalStickeringMask] = await Promise.all([
946
956
  this.model.twistySceneModel.foundationStickerSprite.get(),
947
957
  this.model.twistySceneModel.hintStickerSprite.get(),
948
- this.model.twistySceneModel.stickering.get()
958
+ this.model.twistySceneModel.stickeringMask.get()
949
959
  ]);
950
- return (await proxyPromise).cube3DShim(() => this.schedulable.scheduleRender(), {
951
- foundationSprite,
952
- hintSprite,
953
- experimentalStickering
954
- });
960
+ return (await proxyPromise).cube3DShim(
961
+ () => this.schedulable.scheduleRender(),
962
+ {
963
+ foundationSprite,
964
+ hintSprite,
965
+ experimentalStickeringMask
966
+ }
967
+ );
955
968
  } else {
956
969
  const [hintFacelets, foundationSprite, hintSprite] = await Promise.all([
957
970
  this.model.twistySceneModel.hintFacelet.get(),
@@ -981,7 +994,10 @@ var Twisty3DPuzzleWrapper = class extends EventTarget {
981
994
  return;
982
995
  }
983
996
  const targets = puzzle.experimentalGetControlTargets();
984
- const [raycaster] = await Promise.all([raycasterPromise]);
997
+ const [raycaster, movePressCancelOptions] = await Promise.all([
998
+ raycasterPromise,
999
+ this.model.twistySceneModel.movePressCancelOptions.get()
1000
+ ]);
985
1001
  const intersects = raycaster.intersectObjects(targets);
986
1002
  if (intersects.length > 0) {
987
1003
  const closestMove = puzzle.getClosestMoveToAxis(
@@ -990,8 +1006,7 @@ var Twisty3DPuzzleWrapper = class extends EventTarget {
990
1006
  );
991
1007
  if (closestMove) {
992
1008
  this.model.experimentalAddMove(closestMove.move, {
993
- coalesce: true,
994
- mod: closestMove.order
1009
+ cancel: movePressCancelOptions
995
1010
  });
996
1011
  } else {
997
1012
  console.info("Skipping move!");
@@ -1630,33 +1645,41 @@ customElementsShim.define("twisty-scrubber", TwistyScrubber);
1630
1645
  // src/cubing/twisty/views/screenshot.ts
1631
1646
  var cachedCamera = null;
1632
1647
  async function screenshot(model, options) {
1648
+ const [
1649
+ { PerspectiveCamera, Scene },
1650
+ puzzleLoader,
1651
+ visualizationStrategy,
1652
+ _stickering,
1653
+ _stickeringMaskRequest,
1654
+ _legacyPosition,
1655
+ orbitCoordinates
1656
+ ] = await Promise.all([
1657
+ THREEJS,
1658
+ await model.puzzleLoader.get(),
1659
+ await model.visualizationStrategy.get(),
1660
+ await model.twistySceneModel.stickeringRequest.get(),
1661
+ await model.twistySceneModel.stickeringMaskRequest.get(),
1662
+ await model.legacyPosition.get(),
1663
+ await model.twistySceneModel.orbitCoordinates.get()
1664
+ ]);
1633
1665
  const width = options?.width ?? 2048;
1634
1666
  const height = options?.height ?? 2048;
1635
1667
  const aspectRatio = width / height;
1636
1668
  const camera = cachedCamera ?? (cachedCamera = await (async () => {
1637
- return new (await THREEJS).PerspectiveCamera(20, aspectRatio, 0.1, 20);
1669
+ return new PerspectiveCamera(20, aspectRatio, 0.1, 20);
1638
1670
  })());
1639
- const scene = new (await THREEJS).Scene();
1671
+ const scene = new Scene();
1640
1672
  const twisty3DWrapper = new Twisty3DPuzzleWrapper(
1641
1673
  model,
1642
1674
  { scheduleRender: () => {
1643
1675
  } },
1644
- await model.puzzleLoader.get(),
1645
- await model.visualizationStrategy.get()
1676
+ puzzleLoader,
1677
+ visualizationStrategy
1646
1678
  );
1647
- await model.twistySceneModel.stickering.get();
1648
- await new Promise((resolve) => setTimeout(resolve, 1e3));
1649
- await model.legacyPosition.get();
1650
1679
  scene.add(await twisty3DWrapper.twisty3DPuzzle());
1651
- const orbitCoordinates = await model.twistySceneModel.orbitCoordinates.get();
1652
1680
  await setCameraFromOrbitCoordinates(camera, orbitCoordinates);
1653
- const renderer = new (await THREEJS).WebGLRenderer({
1654
- antialias: true,
1655
- alpha: true
1656
- });
1657
- renderer.setSize(width, height);
1658
- renderer.render(scene, camera);
1659
- const dataURL = renderer.domElement.toDataURL();
1681
+ const rendererCanvas = await rawRenderPooled(width, height, scene, camera);
1682
+ const dataURL = rendererCanvas.toDataURL();
1660
1683
  const defaultFilename = await getDefaultFilename(model);
1661
1684
  return {
1662
1685
  dataURL,
@@ -2067,9 +2090,7 @@ var SimpleAlgIndexer = class {
2067
2090
  return i;
2068
2091
  }
2069
2092
  stateAtIndex(index) {
2070
- return this.kpuzzle.startState().applyTransformation(
2071
- this.transformationAtIndex(index)
2072
- );
2093
+ return this.kpuzzle.startState().applyTransformation(this.transformationAtIndex(index));
2073
2094
  }
2074
2095
  transformationAtIndex(index) {
2075
2096
  let state = this.kpuzzle.identityTransformation();
@@ -2488,19 +2509,19 @@ var DecoratorConstructor = class extends TraversalUp {
2488
2509
  }
2489
2510
  traverseMove(move) {
2490
2511
  const key = move.toString();
2491
- let r = this.cache[key];
2492
- if (r) {
2493
- return r;
2512
+ let r2 = this.cache[key];
2513
+ if (r2) {
2514
+ return r2;
2494
2515
  }
2495
2516
  const transformation = this.kpuzzle.moveToTransformation(move);
2496
- r = new AlgWalkterDecoration(
2517
+ r2 = new AlgWalkterDecoration(
2497
2518
  1,
2498
2519
  this.durationFn.traverseAlgNode(move),
2499
2520
  transformation,
2500
2521
  transformation.invert()
2501
2522
  );
2502
- this.cache[key] = r;
2503
- return r;
2523
+ this.cache[key] = r2;
2524
+ return r2;
2504
2525
  }
2505
2526
  traverseCommutator(commutator) {
2506
2527
  const decA = this.traverseAlg(commutator.A);
@@ -2508,7 +2529,13 @@ var DecoratorConstructor = class extends TraversalUp {
2508
2529
  const AB = decA.forward.applyTransformation(decB.forward);
2509
2530
  const ApBp = decA.backward.applyTransformation(decB.backward);
2510
2531
  const ABApBp = AB.applyTransformation(ApBp);
2511
- const dec = new AlgWalkterDecoration(2 * (decA.moveCount + decB.moveCount), 2 * (decA.duration + decB.duration), ABApBp, ABApBp.invert(), [decA, decB]);
2532
+ const dec = new AlgWalkterDecoration(
2533
+ 2 * (decA.moveCount + decB.moveCount),
2534
+ 2 * (decA.duration + decB.duration),
2535
+ ABApBp,
2536
+ ABApBp.invert(),
2537
+ [decA, decB]
2538
+ );
2512
2539
  return this.mult(dec, 1, [dec, decA, decB]);
2513
2540
  }
2514
2541
  traverseConjugate(conjugate) {
@@ -2516,10 +2543,13 @@ var DecoratorConstructor = class extends TraversalUp {
2516
2543
  const decB = this.traverseAlg(conjugate.B);
2517
2544
  const AB = decA.forward.applyTransformation(decB.forward);
2518
2545
  const ABAp = AB.applyTransformation(decA.backward);
2519
- const dec = new AlgWalkterDecoration(2 * decA.moveCount + decB.moveCount, 2 * decA.duration + decB.duration, ABAp, ABAp.invert(), [
2520
- decA,
2521
- decB
2522
- ]);
2546
+ const dec = new AlgWalkterDecoration(
2547
+ 2 * decA.moveCount + decB.moveCount,
2548
+ 2 * decA.duration + decB.duration,
2549
+ ABAp,
2550
+ ABAp.invert(),
2551
+ [decA, decB]
2552
+ );
2523
2553
  return this.mult(dec, 1, [dec, decA, decB]);
2524
2554
  }
2525
2555
  traversePause(pause) {
@@ -2594,8 +2624,8 @@ var AlgWalker = class extends TraversalDownUp {
2594
2624
  this.moveDuration = 0;
2595
2625
  this.back = false;
2596
2626
  this.st = this.kpuzzle.identityTransformation();
2597
- const r = this.algOrAlgNode.is(Alg) ? this.traverseAlg(this.algOrAlgNode, this.root) : this.traverseAlgNode(this.algOrAlgNode, this.root);
2598
- return r;
2627
+ const r2 = this.algOrAlgNode.is(Alg) ? this.traverseAlg(this.algOrAlgNode, this.root) : this.traverseAlgNode(this.algOrAlgNode, this.root);
2628
+ return r2;
2599
2629
  }
2600
2630
  traverseAlg(alg, wd) {
2601
2631
  if (!this.firstcheck(wd)) {
@@ -3229,10 +3259,94 @@ var SpriteProp = class extends TwistyPropDerived {
3229
3259
  }
3230
3260
  };
3231
3261
 
3232
- // src/cubing/twisty/model/props/puzzle/display/StickeringProp.ts
3233
- var StickeringProp = class extends SimpleTwistyPropSource {
3262
+ // src/cubing/twisty/model/props/puzzle/display/StickeringMaskProp.ts
3263
+ var r = {
3264
+ facelets: ["regular", "regular", "regular", "regular", "regular"]
3265
+ };
3266
+ async function fullStickeringMask(puzzleLoader) {
3267
+ const { definition } = await puzzleLoader.kpuzzle();
3268
+ const fullStickeringMask2 = { orbits: {} };
3269
+ for (const [orbitName, orbitDef] of Object.entries(definition.orbits)) {
3270
+ fullStickeringMask2.orbits[orbitName] = {
3271
+ pieces: new Array(orbitDef.numPieces).fill(r)
3272
+ };
3273
+ }
3274
+ return fullStickeringMask2;
3275
+ }
3276
+ var StickeringMaskProp = class extends TwistyPropDerived {
3234
3277
  getDefaultValue() {
3235
- return "full";
3278
+ return { orbits: {} };
3279
+ }
3280
+ async derive(inputs) {
3281
+ if (inputs.stickeringMaskRequest) {
3282
+ return inputs.stickeringMaskRequest;
3283
+ }
3284
+ if (inputs.stickeringRequest === "picture") {
3285
+ return {
3286
+ specialBehaviour: "picture",
3287
+ orbits: {}
3288
+ };
3289
+ }
3290
+ return inputs.puzzleLoader.stickeringMask?.(
3291
+ inputs.stickeringRequest ?? "full"
3292
+ ) ?? fullStickeringMask(inputs.puzzleLoader);
3293
+ }
3294
+ };
3295
+
3296
+ // src/cubing/twisty/model/props/puzzle/display/parseSerializedStickeringMask.ts
3297
+ var charMap = {
3298
+ "-": "Regular" /* Regular */,
3299
+ D: "Dim" /* Dim */,
3300
+ I: "Ignored" /* Ignored */,
3301
+ X: "Invisible" /* Invisible */,
3302
+ O: "IgnoreNonPrimary" /* IgnoreNonPrimary */,
3303
+ P: "PermuteNonPrimary" /* PermuteNonPrimary */,
3304
+ o: "Ignoriented" /* Ignoriented */,
3305
+ "?": "OrientationWithoutPermutation" /* OrientationWithoutPermutation */,
3306
+ "@": "Regular" /* Regular */
3307
+ };
3308
+ function parseSerializedStickeringMask(serializedStickeringMask) {
3309
+ const stickeringMask = {
3310
+ orbits: {}
3311
+ };
3312
+ const serializedOrbits = serializedStickeringMask.split(",");
3313
+ for (const serializedOrbit of serializedOrbits) {
3314
+ const [orbitName, serializedOrbitPieces, ...rest] = serializedOrbit.split(":");
3315
+ if (rest.length > 0) {
3316
+ throw new Error(
3317
+ `Invalid serialized orbit stickering mask (too many colons): \`${serializedOrbit}\``
3318
+ );
3319
+ }
3320
+ const pieces = [];
3321
+ stickeringMask.orbits[orbitName] = { pieces };
3322
+ for (const char of serializedOrbitPieces) {
3323
+ const pieceStickering = charMap[char];
3324
+ pieces.push(getPieceStickeringMask(pieceStickering));
3325
+ }
3326
+ }
3327
+ return stickeringMask;
3328
+ }
3329
+
3330
+ // src/cubing/twisty/model/props/puzzle/display/StickeringMaskRequestProp.ts
3331
+ var StickeringMaskRequestProp = class extends TwistyPropSource {
3332
+ getDefaultValue() {
3333
+ return null;
3334
+ }
3335
+ derive(input) {
3336
+ if (input === null) {
3337
+ return null;
3338
+ } else if (typeof input === "string") {
3339
+ return parseSerializedStickeringMask(input);
3340
+ } else {
3341
+ return input;
3342
+ }
3343
+ }
3344
+ };
3345
+
3346
+ // src/cubing/twisty/model/props/puzzle/display/StickeringRequestProp.ts
3347
+ var StickeringRequestProp = class extends SimpleTwistyPropSource {
3348
+ getDefaultValue() {
3349
+ return null;
3236
3350
  }
3237
3351
  };
3238
3352
 
@@ -3243,6 +3357,13 @@ var DragInputProp = class extends SimpleTwistyPropSource {
3243
3357
  }
3244
3358
  };
3245
3359
 
3360
+ // src/cubing/twisty/model/props/puzzle/state/MovePressCancelOptions.ts
3361
+ var MovePressCancelOptions = class extends SimpleTwistyPropSource {
3362
+ getDefaultValue() {
3363
+ return {};
3364
+ }
3365
+ };
3366
+
3246
3367
  // src/cubing/twisty/model/props/puzzle/state/MovePressInputProp.ts
3247
3368
  var MovePressInputProp = class extends SimpleTwistyPropSource {
3248
3369
  getDefaultValue() {
@@ -3384,8 +3505,10 @@ var TwistySceneModel = class {
3384
3505
  this.hintStickerSpriteURL = new URLProp();
3385
3506
  this.latitudeLimit = new LatitudeLimitProp();
3386
3507
  this.movePressInput = new MovePressInputProp();
3508
+ this.movePressCancelOptions = new MovePressCancelOptions();
3387
3509
  this.orbitCoordinatesRequest = new OrbitCoordinatesRequestProp();
3388
- this.stickering = new StickeringProp();
3510
+ this.stickeringMaskRequest = new StickeringMaskRequestProp();
3511
+ this.stickeringRequest = new StickeringRequestProp();
3389
3512
  this.foundationStickerSprite = new SpriteProp({
3390
3513
  spriteURL: this.foundationStickerSpriteURL
3391
3514
  });
@@ -3398,6 +3521,11 @@ var TwistySceneModel = class {
3398
3521
  puzzleID: twistyPlayerModel.puzzleID,
3399
3522
  strategy: twistyPlayerModel.visualizationStrategy
3400
3523
  });
3524
+ this.stickeringMask = new StickeringMaskProp({
3525
+ stickeringMaskRequest: this.stickeringMaskRequest,
3526
+ stickeringRequest: this.stickeringRequest,
3527
+ puzzleLoader: twistyPlayerModel.puzzleLoader
3528
+ });
3401
3529
  }
3402
3530
  };
3403
3531
 
@@ -3525,7 +3653,7 @@ var TwistyPlayerModel = class {
3525
3653
  alg,
3526
3654
  setup,
3527
3655
  anchor,
3528
- experimentalStickering
3656
+ experimentalStickeringRequest
3529
3657
  ] = await Promise.all([
3530
3658
  this.viewerLink.get(),
3531
3659
  this.puzzleID.get(),
@@ -3533,7 +3661,7 @@ var TwistyPlayerModel = class {
3533
3661
  this.alg.get(),
3534
3662
  this.setupAlg.get(),
3535
3663
  this.setupAnchor.get(),
3536
- this.twistySceneModel.stickering.get()
3664
+ this.twistySceneModel.stickeringRequest.get()
3537
3665
  ]);
3538
3666
  const isExplorer = viewerLink === "experimental-twizzle-explorer";
3539
3667
  const url = new URL(
@@ -3548,8 +3676,11 @@ var TwistyPlayerModel = class {
3548
3676
  if (anchor !== "start") {
3549
3677
  url.searchParams.set("setup-anchor", anchor);
3550
3678
  }
3551
- if (experimentalStickering !== "full") {
3552
- url.searchParams.set("experimental-stickering", experimentalStickering);
3679
+ if (experimentalStickeringRequest !== "full" && experimentalStickeringRequest !== null) {
3680
+ url.searchParams.set(
3681
+ "experimental-stickering",
3682
+ experimentalStickeringRequest
3683
+ );
3553
3684
  }
3554
3685
  if (isExplorer && puzzleDescription !== NO_VALUE) {
3555
3686
  url.searchParams.set("puzzle-description", puzzleDescription);
@@ -3558,7 +3689,7 @@ var TwistyPlayerModel = class {
3558
3689
  }
3559
3690
  return url.toString();
3560
3691
  }
3561
- experimentalAddAlgLeaf(algLeaf, options = {}) {
3692
+ experimentalAddAlgLeaf(algLeaf, options) {
3562
3693
  const maybeMove = algLeaf.as(Move);
3563
3694
  if (maybeMove) {
3564
3695
  this.experimentalAddMove(maybeMove, options);
@@ -3573,14 +3704,17 @@ var TwistyPlayerModel = class {
3573
3704
  );
3574
3705
  }
3575
3706
  }
3576
- experimentalAddMove(flexibleMove, options = {}) {
3707
+ experimentalAddMove(flexibleMove, options) {
3577
3708
  const move = typeof flexibleMove === "string" ? new Move(flexibleMove) : flexibleMove;
3578
3709
  this.alg.set(
3579
3710
  (async () => {
3580
- const alg = (await this.alg.get()).alg;
3711
+ const [{ alg }, puzzleLoader] = await Promise.all([
3712
+ this.alg.get(),
3713
+ this.puzzleLoader.get()
3714
+ ]);
3581
3715
  const newAlg = experimentalAppendMove(alg, move, {
3582
- coalesce: options?.coalesce,
3583
- mod: options?.mod
3716
+ ...options,
3717
+ puzzleLoader
3584
3718
  });
3585
3719
  this.timestampRequest.set("end");
3586
3720
  this.catchUpMove.set({
@@ -3591,6 +3725,27 @@ var TwistyPlayerModel = class {
3591
3725
  })()
3592
3726
  );
3593
3727
  }
3728
+ experimentalRemoveFinalChild() {
3729
+ this.alg.set(
3730
+ (async () => {
3731
+ const alg = (await this.alg.get()).alg;
3732
+ const children = Array.from(alg.childAlgNodes());
3733
+ const [finalChild] = children.splice(-1);
3734
+ if (!finalChild) {
3735
+ return alg;
3736
+ }
3737
+ this.timestampRequest.set("end");
3738
+ const finalChildMove = finalChild.as(Move);
3739
+ if (finalChildMove) {
3740
+ this.catchUpMove.set({
3741
+ move: finalChildMove.invert(),
3742
+ amount: 0
3743
+ });
3744
+ }
3745
+ return new Alg(children);
3746
+ })()
3747
+ );
3748
+ }
3594
3749
  };
3595
3750
 
3596
3751
  // src/cubing/twisty/views/TwistyPlayerSettable.ts
@@ -3648,10 +3803,18 @@ var TwistyPlayerSettable = class extends ManagedCustomElement {
3648
3803
  throw err("hintFacelets");
3649
3804
  }
3650
3805
  set experimentalStickering(stickering) {
3651
- this.experimentalModel.twistySceneModel.stickering.set(stickering);
3806
+ this.experimentalModel.twistySceneModel.stickeringRequest.set(stickering);
3652
3807
  }
3653
3808
  get experimentalStickering() {
3654
- throw err("stickering");
3809
+ throw err("experimentalStickering");
3810
+ }
3811
+ set experimentalStickeringMaskOrbits(stickeringMask) {
3812
+ this.experimentalModel.twistySceneModel.stickeringMaskRequest.set(
3813
+ stickeringMask
3814
+ );
3815
+ }
3816
+ get experimentalStickeringMaskOrbits() {
3817
+ throw err("experimentalStickeringMaskOrbits");
3655
3818
  }
3656
3819
  set backView(backView) {
3657
3820
  this.experimentalModel.backView.set(backView);
@@ -3707,6 +3870,14 @@ var TwistyPlayerSettable = class extends ManagedCustomElement {
3707
3870
  get experimentalMovePressInput() {
3708
3871
  throw err("experimentalMovePressInput");
3709
3872
  }
3873
+ set experimentalMovePressCancelOptions(movePressCancelOptions) {
3874
+ this.experimentalModel.twistySceneModel.movePressCancelOptions.set(
3875
+ movePressCancelOptions
3876
+ );
3877
+ }
3878
+ get experimentalMovePressCancelOptions() {
3879
+ throw err("experimentalMovePressCancelOptions");
3880
+ }
3710
3881
  set cameraLatitude(latitude) {
3711
3882
  this.experimentalModel.twistySceneModel.orbitCoordinatesRequest.set({
3712
3883
  latitude
@@ -3797,6 +3968,7 @@ var twistyPlayerAttributeMap = {
3797
3968
  visualization: "visualization",
3798
3969
  "hint-facelets": "hintFacelets",
3799
3970
  "experimental-stickering": "experimentalStickering",
3971
+ "experimental-stickering-mask-orbits": "experimentalStickeringMaskOrbits",
3800
3972
  background: "background",
3801
3973
  "control-panel": "controlPanel",
3802
3974
  "back-view": "backView",
@@ -3817,6 +3989,9 @@ var twistyPlayerAttributeMap = {
3817
3989
  var configKeys = Object.fromEntries(
3818
3990
  Object.values(twistyPlayerAttributeMap).map((s) => [s, true])
3819
3991
  );
3992
+ var propOnly = {
3993
+ experimentalMovePressCancelOptions: true
3994
+ };
3820
3995
  var TwistyPlayer = class extends TwistyPlayerSettable {
3821
3996
  constructor(config = {}) {
3822
3997
  super();
@@ -3841,7 +4016,7 @@ var TwistyPlayer = class extends TwistyPlayerSettable {
3841
4016
  this.#initial3DVisualizationWrapper = new InitialValueTracker();
3842
4017
  this.#visualizationStrategy = null;
3843
4018
  for (const [propName, value] of Object.entries(config)) {
3844
- if (!configKeys[propName]) {
4019
+ if (!(configKeys[propName] || propOnly[propName])) {
3845
4020
  console.warn(`Invalid config passed to TwistyPlayer: ${propName}`);
3846
4021
  break;
3847
4022
  }
@@ -3863,13 +4038,15 @@ var TwistyPlayer = class extends TwistyPlayerSettable {
3863
4038
  );
3864
4039
  this.addElement(this.#errorElem).classList.add("error-elem");
3865
4040
  this.#errorElem.textContent = "Error";
3866
- this.experimentalModel.userVisibleErrorTracker.addFreshListener((userVisibleError) => {
3867
- const errorString = userVisibleError.errors[0] ?? null;
3868
- this.contentWrapper.classList.toggle("error", !!errorString);
3869
- if (errorString) {
3870
- this.#errorElem.textContent = errorString;
4041
+ this.experimentalModel.userVisibleErrorTracker.addFreshListener(
4042
+ (userVisibleError) => {
4043
+ const errorString = userVisibleError.errors[0] ?? null;
4044
+ this.contentWrapper.classList.toggle("error", !!errorString);
4045
+ if (errorString) {
4046
+ this.#errorElem.textContent = errorString;
4047
+ }
3871
4048
  }
3872
- });
4049
+ );
3873
4050
  const scrubber = new TwistyScrubber(
3874
4051
  this.experimentalModel,
3875
4052
  this.controller
@@ -3881,15 +4058,19 @@ var TwistyPlayer = class extends TwistyPlayerSettable {
3881
4058
  this
3882
4059
  );
3883
4060
  this.contentWrapper.appendChild(this.buttons);
3884
- this.experimentalModel.twistySceneModel.background.addFreshListener((backgroundTheme) => {
3885
- this.contentWrapper.classList.toggle(
3886
- "checkered",
3887
- backgroundTheme !== "none"
3888
- );
3889
- });
3890
- this.experimentalModel.controlPanel.addFreshListener((controlPanel) => {
3891
- this.#controlsManager.setValue(controlPanel);
3892
- });
4061
+ this.experimentalModel.twistySceneModel.background.addFreshListener(
4062
+ (backgroundTheme) => {
4063
+ this.contentWrapper.classList.toggle(
4064
+ "checkered",
4065
+ backgroundTheme !== "none"
4066
+ );
4067
+ }
4068
+ );
4069
+ this.experimentalModel.controlPanel.addFreshListener(
4070
+ (controlPanel) => {
4071
+ this.#controlsManager.setValue(controlPanel);
4072
+ }
4073
+ );
3893
4074
  this.experimentalModel.visualizationStrategy.addFreshListener(
3894
4075
  this.#setVisualizationWrapper.bind(this)
3895
4076
  );
@@ -3991,10 +4172,10 @@ var TwistyPlayer = class extends TwistyPlayerSettable {
3991
4172
  togglePlay(play) {
3992
4173
  this.controller.togglePlay(play);
3993
4174
  }
3994
- experimentalAddMove(flexibleMove, options = {}) {
4175
+ experimentalAddMove(flexibleMove, options) {
3995
4176
  this.experimentalModel.experimentalAddMove(flexibleMove, options);
3996
4177
  }
3997
- experimentalAddAlgLeaf(algLeaf, options = {}) {
4178
+ experimentalAddAlgLeaf(algLeaf, options) {
3998
4179
  this.experimentalModel.experimentalAddAlgLeaf(algLeaf, options);
3999
4180
  }
4000
4181
  static get observedAttributes() {
@@ -4004,6 +4185,9 @@ var TwistyPlayer = class extends TwistyPlayerSettable {
4004
4185
  }
4005
4186
  return observed;
4006
4187
  }
4188
+ experimentalRemoveFinalChild() {
4189
+ this.experimentalModel.experimentalRemoveFinalChild();
4190
+ }
4007
4191
  attributeChangedCallback(attributeName, _oldValue, newValue) {
4008
4192
  if (attributeName.startsWith(DATA_ATTRIBUTE_PREFIX)) {
4009
4193
  attributeName = attributeName.slice(DATA_ATTRIBUTE_PREFIX.length);
@@ -4408,28 +4592,34 @@ var TwistyAlgViewer = class extends HTMLElementShim {
4408
4592
  throw new Error("clearing twistyPlayer is not supported");
4409
4593
  }
4410
4594
  this.#twistyPlayer = twistyPlayer;
4411
- this.#twistyPlayer.experimentalModel.alg.addFreshListener((algWithIssues) => {
4412
- this.setAlg(algWithIssues.alg);
4413
- });
4595
+ this.#twistyPlayer.experimentalModel.alg.addFreshListener(
4596
+ (algWithIssues) => {
4597
+ this.setAlg(algWithIssues.alg);
4598
+ }
4599
+ );
4414
4600
  const sourceAlg = (await this.#twistyPlayer.experimentalModel.alg.get()).alg;
4415
4601
  const parsedAlg = "startCharIndex" in sourceAlg ? sourceAlg : Alg.fromString(sourceAlg.toString());
4416
4602
  this.setAlg(parsedAlg);
4417
- twistyPlayer.experimentalModel.currentMoveInfo.addFreshListener((currentMoveInfo) => {
4418
- let moveInfo = currentMoveInfo.currentMoves[0];
4419
- moveInfo ?? (moveInfo = currentMoveInfo.movesStarting[0]);
4420
- moveInfo ?? (moveInfo = currentMoveInfo.movesFinishing[0]);
4421
- if (!moveInfo) {
4422
- this.highlighter.set(null);
4423
- } else {
4424
- const mainCurrentMove = moveInfo.move;
4425
- this.highlighter.set(mainCurrentMove);
4603
+ twistyPlayer.experimentalModel.currentMoveInfo.addFreshListener(
4604
+ (currentMoveInfo) => {
4605
+ let moveInfo = currentMoveInfo.currentMoves[0];
4606
+ moveInfo ?? (moveInfo = currentMoveInfo.movesStarting[0]);
4607
+ moveInfo ?? (moveInfo = currentMoveInfo.movesFinishing[0]);
4608
+ if (!moveInfo) {
4609
+ this.highlighter.set(null);
4610
+ } else {
4611
+ const mainCurrentMove = moveInfo.move;
4612
+ this.highlighter.set(mainCurrentMove);
4613
+ }
4426
4614
  }
4427
- });
4428
- twistyPlayer.experimentalModel.detailedTimelineInfo.addFreshListener((detailedTimelineInfo) => {
4429
- if (detailedTimelineInfo.timestamp !== this.lastClickTimestamp) {
4430
- this.lastClickTimestamp = null;
4615
+ );
4616
+ twistyPlayer.experimentalModel.detailedTimelineInfo.addFreshListener(
4617
+ (detailedTimelineInfo) => {
4618
+ if (detailedTimelineInfo.timestamp !== this.lastClickTimestamp) {
4619
+ this.lastClickTimestamp = null;
4620
+ }
4431
4621
  }
4432
- });
4622
+ );
4433
4623
  }
4434
4624
  async jumpToIndex(index, offsetIntoMove) {
4435
4625
  const twistyPlayer = this.#twistyPlayer;
@@ -4765,11 +4955,13 @@ var TwistyAlgEditor = class extends ManagedCustomElement {
4765
4955
  }
4766
4956
  this.#twistyPlayerProp = options?.twistyPlayerProp ?? "alg";
4767
4957
  if (options?.twistyPlayerProp === "alg") {
4768
- this.model.leafToHighlight.addFreshListener((highlightInfo) => {
4769
- if (highlightInfo) {
4770
- this.highlightLeaf(highlightInfo.leafInfo.leaf);
4958
+ this.model.leafToHighlight.addFreshListener(
4959
+ (highlightInfo) => {
4960
+ if (highlightInfo) {
4961
+ this.highlightLeaf(highlightInfo.leafInfo.leaf);
4962
+ }
4771
4963
  }
4772
- });
4964
+ );
4773
4965
  }
4774
4966
  }
4775
4967
  #textarea;
@@ -4872,61 +5064,65 @@ var TwistyAlgEditor = class extends ManagedCustomElement {
4872
5064
  this.algString = this.#algProp ? (await this.#algProp.get()).alg.toString() : "";
4873
5065
  })();
4874
5066
  if (this.#twistyPlayerProp === "alg") {
4875
- this.#twistyPlayer?.experimentalModel.puzzleAlg.addFreshListener((algWithIssues) => {
4876
- if (algWithIssues.issues.errors.length === 0) {
4877
- this.setAlgIssueClassForPuzzle(
4878
- algWithIssues.issues.warnings.length === 0 ? "none" : "warning"
4879
- );
4880
- const newAlg = algWithIssues.alg;
4881
- const oldAlg = Alg.fromString(this.algString);
4882
- if (!newAlg.isIdentical(oldAlg)) {
4883
- this.algString = newAlg.toString();
4884
- this.onInput();
5067
+ this.#twistyPlayer?.experimentalModel.puzzleAlg.addFreshListener(
5068
+ (algWithIssues) => {
5069
+ if (algWithIssues.issues.errors.length === 0) {
5070
+ this.setAlgIssueClassForPuzzle(
5071
+ algWithIssues.issues.warnings.length === 0 ? "none" : "warning"
5072
+ );
5073
+ const newAlg = algWithIssues.alg;
5074
+ const oldAlg = Alg.fromString(this.algString);
5075
+ if (!newAlg.isIdentical(oldAlg)) {
5076
+ this.algString = newAlg.toString();
5077
+ this.onInput();
5078
+ } else {
5079
+ }
4885
5080
  } else {
5081
+ this.setAlgIssueClassForPuzzle("error");
4886
5082
  }
4887
- } else {
4888
- this.setAlgIssueClassForPuzzle("error");
4889
5083
  }
4890
- });
4891
- this.model.leafToHighlight.addFreshListener(async (highlightInfo) => {
4892
- if (highlightInfo === null) {
4893
- return;
4894
- }
4895
- const [indexer, timestampRequest] = await Promise.all([
4896
- await twistyPlayer.experimentalModel.indexer.get(),
4897
- await twistyPlayer.experimentalModel.timestampRequest.get()
4898
- ]);
4899
- if (timestampRequest === "opposite-anchor" && !this.#onInputHasFired) {
4900
- return;
4901
- }
4902
- const moveStartTimestamp = indexer.indexToMoveStartTimestamp(
4903
- highlightInfo.leafInfo.idx
4904
- );
4905
- const duration = indexer.moveDuration(highlightInfo.leafInfo.idx);
4906
- let newTimestamp;
4907
- switch (highlightInfo.where) {
4908
- case "before": {
4909
- newTimestamp = moveStartTimestamp;
4910
- break;
5084
+ );
5085
+ this.model.leafToHighlight.addFreshListener(
5086
+ async (highlightInfo) => {
5087
+ if (highlightInfo === null) {
5088
+ return;
4911
5089
  }
4912
- case "start":
4913
- case "inside": {
4914
- newTimestamp = moveStartTimestamp + duration / 4;
4915
- break;
5090
+ const [indexer, timestampRequest] = await Promise.all([
5091
+ await twistyPlayer.experimentalModel.indexer.get(),
5092
+ await twistyPlayer.experimentalModel.timestampRequest.get()
5093
+ ]);
5094
+ if (timestampRequest === "opposite-anchor" && !this.#onInputHasFired) {
5095
+ return;
4916
5096
  }
4917
- case "end":
4918
- case "after": {
4919
- newTimestamp = moveStartTimestamp + duration;
4920
- break;
5097
+ const moveStartTimestamp = indexer.indexToMoveStartTimestamp(
5098
+ highlightInfo.leafInfo.idx
5099
+ );
5100
+ const duration = indexer.moveDuration(highlightInfo.leafInfo.idx);
5101
+ let newTimestamp;
5102
+ switch (highlightInfo.where) {
5103
+ case "before": {
5104
+ newTimestamp = moveStartTimestamp;
5105
+ break;
5106
+ }
5107
+ case "start":
5108
+ case "inside": {
5109
+ newTimestamp = moveStartTimestamp + duration / 4;
5110
+ break;
5111
+ }
5112
+ case "end":
5113
+ case "after": {
5114
+ newTimestamp = moveStartTimestamp + duration;
5115
+ break;
5116
+ }
5117
+ default:
5118
+ console.log("invalid where");
5119
+ throw new Error("Invalid where!");
5120
+ }
5121
+ if (!this.debugNeverRequestTimestamp) {
5122
+ twistyPlayer.experimentalModel.timestampRequest.set(newTimestamp);
4921
5123
  }
4922
- default:
4923
- console.log("invalid where");
4924
- throw new Error("Invalid where!");
4925
- }
4926
- if (!this.debugNeverRequestTimestamp) {
4927
- twistyPlayer.experimentalModel.timestampRequest.set(newTimestamp);
4928
5124
  }
4929
- });
5125
+ );
4930
5126
  twistyPlayer.experimentalModel.currentLeavesSimplified.addFreshListener(
4931
5127
  async (currentLeavesSimplified) => {
4932
5128
  const indexer = await twistyPlayer.experimentalModel.indexer.get();