@houstonp/rubiks-cube 2.1.0 → 3.0.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 (76) hide show
  1. package/README.md +304 -77
  2. package/package.json +18 -8
  3. package/src/{core.js → core/index.js} +72 -41
  4. package/src/rubiksCube/index.js +3 -0
  5. package/src/rubiksCube/rubiksCubeController.js +111 -0
  6. package/src/{three → rubiksCube3D}/centerPiece.js +37 -2
  7. package/src/{three → rubiksCube3D}/cornerPiece.js +56 -2
  8. package/src/rubiksCube3D/cubeConfig.js +87 -0
  9. package/src/rubiksCube3D/cubeSettings.js +30 -0
  10. package/src/{three → rubiksCube3D}/edgePiece.js +2 -1
  11. package/src/rubiksCube3D/index.js +3 -0
  12. package/src/rubiksCube3D/rubiksCube3D.js +383 -0
  13. package/src/{three → rubiksCube3D}/sticker.js +5 -4
  14. package/src/state/index.js +4 -0
  15. package/src/state/rubiksCubeState.js +471 -0
  16. package/src/state/slice.js +236 -0
  17. package/src/state/stickerState.js +185 -0
  18. package/src/{camera → webComponent}/cameraState.js +17 -25
  19. package/src/webComponent/constants.js +67 -0
  20. package/src/webComponent/index.js +7 -0
  21. package/src/webComponent/rubiksCubeElement.js +379 -0
  22. package/src/{settings.js → webComponent/settings.js} +36 -23
  23. package/tests/common.js +3 -20
  24. package/tests/core.test.js +56 -0
  25. package/tests/rubiksCube.solves.test.js +41 -0
  26. package/tests/rubiksCube3D.solves.test.js +185 -0
  27. package/tests/rubiksCubeState.solves.test.js +35 -0
  28. package/tests/testScrambles.js +194 -0
  29. package/types/{core.d.ts → core/index.d.ts} +45 -48
  30. package/types/rubiksCube/index.d.ts +3 -0
  31. package/types/rubiksCube/rubiksCubeController.d.ts +62 -0
  32. package/types/rubiksCube3D/centerPiece.d.ts +27 -0
  33. package/types/rubiksCube3D/cornerPiece.d.ts +38 -0
  34. package/types/rubiksCube3D/cubeConfig.d.ts +32 -0
  35. package/types/rubiksCube3D/cubeSettings.d.ts +33 -0
  36. package/types/{three → rubiksCube3D}/edgePiece.d.ts +5 -3
  37. package/types/rubiksCube3D/index.d.ts +3 -0
  38. package/types/rubiksCube3D/rubiksCube3D.d.ts +120 -0
  39. package/types/rubiksCube3D/sticker.d.ts +18 -0
  40. package/types/state/index.d.ts +5 -0
  41. package/types/state/rubiksCubeState.d.ts +108 -0
  42. package/types/state/slice.d.ts +46 -0
  43. package/types/state/stickerState.d.ts +34 -0
  44. package/types/webComponent/cameraState.d.ts +22 -0
  45. package/types/webComponent/constants.d.ts +57 -0
  46. package/types/webComponent/index.d.ts +6 -0
  47. package/types/webComponent/rubiksCubeElement.d.ts +89 -0
  48. package/types/{settings.d.ts → webComponent/settings.d.ts} +5 -8
  49. package/src/cube/animationSlice.js +0 -205
  50. package/src/cube/animationState.js +0 -96
  51. package/src/cube/cubeSettings.js +0 -19
  52. package/src/cube/cubeState.js +0 -337
  53. package/src/cube/stickerState.js +0 -188
  54. package/src/index.js +0 -621
  55. package/src/three/cube.js +0 -492
  56. package/tests/cube.five.test.js +0 -126
  57. package/tests/cube.four.test.js +0 -126
  58. package/tests/cube.seven.test.js +0 -126
  59. package/tests/cube.six.test.js +0 -126
  60. package/tests/cube.three.test.js +0 -151
  61. package/tests/cube.two.test.js +0 -125
  62. package/types/camera/cameraState.d.ts +0 -19
  63. package/types/cube/animationSlice.d.ts +0 -26
  64. package/types/cube/animationState.d.ts +0 -41
  65. package/types/cube/cubeSettings.d.ts +0 -17
  66. package/types/cube/cubeState.d.ts +0 -47
  67. package/types/cube/stickerState.d.ts +0 -21
  68. package/types/index.d.ts +0 -87
  69. package/types/three/centerPiece.d.ts +0 -15
  70. package/types/three/cornerPiece.d.ts +0 -24
  71. package/types/three/cube.d.ts +0 -130
  72. package/types/three/sticker.d.ts +0 -15
  73. /package/src/{debouncer.js → webComponent/debouncer.js} +0 -0
  74. /package/src/{globals.ts → webComponent/globals.ts} +0 -0
  75. /package/types/{debouncer.d.ts → webComponent/debouncer.d.ts} +0 -0
  76. /package/types/{globals.d.ts → webComponent/globals.d.ts} +0 -0
@@ -1,4 +1,36 @@
1
1
  // @ts-check
2
+
3
+ /**
4
+ * reverses the direction of a movement or rotation
5
+ * @template {Movement | Rotation} T
6
+ * @param {T} action
7
+ * @returns {T}
8
+ * */
9
+ export function reverse(action) {
10
+ let reversedAction = action;
11
+ if (action.at(-1) === "'") {
12
+ reversedAction = /** @type {T} */ (action.slice(0, -1));
13
+ } else {
14
+ const newAction = /** @type {T} */ (action + "'");
15
+ reversedAction = newAction;
16
+ }
17
+ return reversedAction;
18
+ }
19
+
20
+ /**
21
+ * Translates notation meant for a 3x3 into notation a big cube. This is so that 3x3 algorithms can be used on a big cube if desired. eg. for a 6x6 r -> 5r
22
+ * @template {Movement | Rotation} T
23
+ * @param {T} action
24
+ * @param {CubeType} cubeType
25
+ * @returns {T}
26
+ * */
27
+ export function translate(action, cubeType) {
28
+ if (Object.values(Movements.Wide).includes(/** @type {WideMove} **/ (action))) {
29
+ return /** @type {T} */ (LayerCount[cubeType] - 1 + action);
30
+ }
31
+ return action;
32
+ }
33
+
2
34
  /**
3
35
  * @typedef {typeof Movements.Single[keyof typeof Movements.Single]} SingleMove
4
36
  * @typedef {typeof Movements.Wide[keyof typeof Movements.Wide]} WideMove
@@ -71,7 +103,7 @@ export const Movements = Object.freeze({
71
103
  u2: 'u2',
72
104
  uP: "u'",
73
105
  Dw: 'Dw',
74
- Dw2: 'D2',
106
+ Dw2: 'Dw2',
75
107
  DwP: "Dw'",
76
108
  d: 'd',
77
109
  d2: 'd2',
@@ -357,6 +389,27 @@ export const Movements = Object.freeze({
357
389
  D2: '6D2',
358
390
  DP: "6D'",
359
391
  }),
392
+ /**
393
+ * Build a layer-range move for big-cube notation. e.g. Movements.Range(2, 4, Movements.Wide.Rw) returns '2-4Rw',
394
+ * meaning "rotate layers 2 through 4 from the right face." Accepts wide moves (`Movements.Wide.*`), face
395
+ * moves (`Movements.Single.{R,L,U,D,F,B}` and modifiers), and slice moves (`Movements.Single.{M,E,S}` and
396
+ * modifiers). Already-prefixed moves (`2R`, `2-4Rw`) are rejected.
397
+ * @param {number} lower
398
+ * @param {number} upper
399
+ * @param {WideMove | SingleMove} baseMove
400
+ * @returns {Movement}
401
+ */
402
+ Range: (lower, upper, baseMove) => {
403
+ if (!Number.isInteger(lower) || !Number.isInteger(upper) || lower < 1 || lower >= upper || upper > 7) {
404
+ throw new Error(`Invalid layer range [${lower}-${upper}]: require integers with 1 <= lower < upper <= 7`);
405
+ }
406
+ const move = /** @type {Movement} */ (`${lower}-${upper}${baseMove}`);
407
+ if (!isMovement(move)) {
408
+ throw new Error(`Invalid range movement: ${move}`);
409
+ }
410
+
411
+ return move;
412
+ },
360
413
  });
361
414
 
362
415
  /**
@@ -398,50 +451,28 @@ export const CubeTypes = Object.freeze({
398
451
  Seven: 'Seven',
399
452
  });
400
453
 
401
- /**
402
- * @typedef {typeof AnimationStyles[keyof typeof AnimationStyles]} AnimationStyle
403
- */
404
- export const AnimationStyles = Object.freeze({
405
- Exponential: 'exponential',
406
- Next: 'next',
407
- Fixed: 'fixed',
408
- Match: 'match',
409
- });
410
-
411
- /**
412
- * @typedef {typeof FaceColours [keyof typeof FaceColours]} FaceColour
413
- */
414
- export const FaceColours = Object.freeze({
415
- U: 'white',
416
- D: 'yellow',
417
- L: '#fc9a05',
418
- R: 'red',
419
- F: '#2cbf13',
420
- B: 'blue',
454
+ export const LayerCount = Object.freeze({
455
+ [CubeTypes.Two]: 2,
456
+ [CubeTypes.Three]: 3,
457
+ [CubeTypes.Four]: 4,
458
+ [CubeTypes.Five]: 5,
459
+ [CubeTypes.Six]: 6,
460
+ [CubeTypes.Seven]: 7,
421
461
  });
422
462
 
423
463
  /**
424
- * @typedef {typeof PeekTypes [keyof typeof PeekTypes]} PeekType
464
+ *
465
+ * @param {string} rotation
425
466
  */
426
- export const PeekTypes = Object.freeze({
427
- Horizontal: 'horizontal',
428
- Vertical: 'vertical',
429
- Right: 'right',
430
- Left: 'left',
431
- Up: 'up',
432
- Down: 'down',
433
- RightUp: 'rightUp',
434
- RightDown: 'rightDown',
435
- LeftUp: 'leftUp',
436
- LeftDown: 'leftDown',
437
- });
467
+ export function IsRotation(rotation) {
468
+ return /^([xyz])(\d)?(\')?$/.test(rotation);
469
+ }
438
470
 
439
471
  /**
440
- * @typedef {typeof PeekStates [keyof typeof PeekStates]} PeekState
472
+ *
473
+ * @param {string} movement
474
+ * @return {boolean}
441
475
  */
442
- export const PeekStates = Object.freeze({
443
- RightUp: 'rightUp',
444
- RightDown: 'rightDown',
445
- LeftUp: 'leftUp',
446
- LeftDown: 'leftDown',
447
- });
476
+ export function isMovement(movement) {
477
+ return /^([1234567]|[123456]-[1234567])?([RLUDFB]w|[RLUDFBMES]|[rludfbmes])([123])?(\')?$/.test(movement);
478
+ }
@@ -0,0 +1,3 @@
1
+ import RubiksCubeController from './rubiksCubeController';
2
+ export { RubiksCubeController };
3
+ /** @typedef {import('./rubiksCubeController').AnimationOptions} AnimationOptions */
@@ -0,0 +1,111 @@
1
+ // @ts-check
2
+ /** @import {Slice} from '../state/slice' */
3
+ /** @import {StickerState} from '../state/stickerState' */
4
+ /** @import {CubeType, Movement, Rotation} from '../core' */
5
+ /**
6
+ * @typedef AnimationOptions
7
+ * @property {boolean} [translate]
8
+ * @property {number} [animationSpeedMs]
9
+ * @property {boolean} [reverse]
10
+ */
11
+ /**
12
+ * @typedef {Object} RubiksCubeViewInterface
13
+ * @property {function(Slice, any=): Promise<void>} slice
14
+ * @property {function(StickerState): void} setState
15
+ * @property {function(): void} reset
16
+ * @property {function(CubeType): void} setType
17
+ **/
18
+
19
+ import { CubeTypes } from '../core';
20
+ import { RubiksCubeState } from '../state';
21
+ import { fromKociemba, toKociemba } from '../state/stickerState';
22
+
23
+ export default class RubiksCubeController {
24
+ /**
25
+ * @param {CubeType} cubeType
26
+ * @param {RubiksCubeViewInterface} view
27
+ * */
28
+ constructor(cubeType, view) {
29
+ this.state = new RubiksCubeState(cubeType);
30
+ this.view = view;
31
+ }
32
+ /**
33
+ * @param {Movement} movement
34
+ * @param {AnimationOptions} [options]
35
+ * @returns {Promise<string>}
36
+ */
37
+ movement(movement, options) {
38
+ const slice = this.state.move(movement, { reverse: options?.reverse, translate: options?.translate });
39
+ if (slice == null) {
40
+ return Promise.reject(new Error(`Invalid movement: ${movement}`));
41
+ }
42
+ return this.view.slice(slice, { animationSpeedMs: options?.animationSpeedMs }).then(() => toKociemba(this.state.getState()));
43
+ }
44
+
45
+ /**
46
+ * @param {Rotation} rotation
47
+ * @param {AnimationOptions} [options]
48
+ * @returns {Promise<string>}
49
+ */
50
+ rotation(rotation, options) {
51
+ const slice = this.state.rotate(rotation, { reverse: options?.reverse });
52
+ if (slice == null) {
53
+ return Promise.reject(new Error(`Invalid rotation: ${rotation}`));
54
+ }
55
+ return this.view.slice(slice, { animationSpeedMs: options?.animationSpeedMs }).then(() => toKociemba(this.state.getState()));
56
+ }
57
+
58
+ /**
59
+ * @param {(Rotation | Movement)[]} actions
60
+ * @param {AnimationOptions} [options]
61
+ * @returns {string}
62
+ */
63
+ do(actions, options) {
64
+ this.state.do(actions, { translate: options?.translate, reverse: options?.reverse });
65
+ this.view.setState(this.state.getState());
66
+ return toKociemba(this.state.getState());
67
+ }
68
+
69
+ /**
70
+ * @returns {string}
71
+ */
72
+ reset() {
73
+ this.state.reset();
74
+ this.view.reset();
75
+ return toKociemba(this.state.getState());
76
+ }
77
+
78
+ /**
79
+ * @param {string} kociembaState
80
+ * @returns {boolean}
81
+ */
82
+ setState(kociembaState) {
83
+ const state = fromKociemba(kociembaState);
84
+ if (state) {
85
+ this.state.setState(state);
86
+ this.view.setState(state);
87
+ return true;
88
+ }
89
+ return false;
90
+ }
91
+
92
+ /**
93
+ * @returns {string}
94
+ */
95
+ getState() {
96
+ return toKociemba(this.state.getState());
97
+ }
98
+
99
+ /**
100
+ * @param {CubeType} cubeType
101
+ * @returns {string}
102
+ */
103
+ setType(cubeType) {
104
+ if (!Object.values(CubeTypes).includes(cubeType)) {
105
+ throw new Error(`Invalid cube type: ${cubeType}`);
106
+ }
107
+ this.state = new RubiksCubeState(cubeType);
108
+ this.view.setType(cubeType);
109
+ return toKociemba(this.state.getState());
110
+ }
111
+ }
@@ -1,9 +1,10 @@
1
1
  // @ts-check
2
- import { BoxGeometry, ExtrudeGeometry, Mesh, MeshBasicMaterial, Object3D } from 'three';
2
+ import { BoxGeometry, ExtrudeGeometry, Mesh, MeshBasicMaterial, MeshStandardMaterial, Object3D, PlaneGeometry, SRGBColorSpace, TextureLoader } from 'three';
3
3
  import { SVGLoader } from 'three/examples/jsm/Addons.js';
4
4
  import { Sticker } from './sticker';
5
+ /** @import {Vector3Like} from 'three' */
5
6
 
6
- /** @typedef {{ positon: import('three').Vector3Like, rotation: import('three').Vector3Like }} CenterPieceUserData */
7
+ /** @typedef {{ positon: Vector3Like, rotation: Vector3Like }} CenterPieceUserData */
7
8
 
8
9
  export class CenterPiece extends Object3D {
9
10
  constructor() {
@@ -18,11 +19,45 @@ export class CenterPiece extends Object3D {
18
19
  this.frontSticker.position.set(0, 0, 0.5);
19
20
  this.frontSticker.rotation.set(0, 0, 0);
20
21
  this.add(this.frontSticker);
22
+
23
+ /** @type {Mesh<PlaneGeometry, MeshStandardMaterial> | null} */
24
+ this.logo = null;
21
25
  }
22
26
 
23
27
  get stickers() {
24
28
  return [this.frontSticker];
25
29
  }
30
+
31
+ /**
32
+ * @param {string} logoPath
33
+ */
34
+ addLogo(logoPath) {
35
+ this.removeLogo();
36
+ const material = new MeshStandardMaterial({
37
+ transparent: true,
38
+ color: 'white',
39
+ metalness: 0,
40
+ roughness: 0.4,
41
+ });
42
+ const mesh = new Mesh(new PlaneGeometry(0.9, 0.9), material);
43
+ mesh.position.set(0, 0, 0.54);
44
+ this.logo = mesh;
45
+ this.add(mesh);
46
+ const texture = new TextureLoader().load(logoPath, (texture) => {
47
+ texture.colorSpace = SRGBColorSpace;
48
+ material.map = texture;
49
+ material.needsUpdate = true;
50
+ texture.anisotropy = 16;
51
+ });
52
+ }
53
+
54
+ removeLogo() {
55
+ if (!this.logo) return;
56
+ this.remove(this.logo);
57
+ this.logo.material.map?.dispose();
58
+ this.logo.material.dispose();
59
+ this.logo = null;
60
+ }
26
61
  }
27
62
 
28
63
  const loader = new SVGLoader();
@@ -1,9 +1,23 @@
1
1
  /// @ts-check
2
- import { BoxGeometry, ExtrudeGeometry, Material, Mesh, MeshBasicMaterial, Object3D } from 'three';
2
+ import {
3
+ BoxGeometry,
4
+ ExtrudeGeometry,
5
+ Material,
6
+ Mesh,
7
+ MeshBasicMaterial,
8
+ MeshStandardMaterial,
9
+ Object3D,
10
+ PlaneGeometry,
11
+ SRGBColorSpace,
12
+ TextureLoader,
13
+ } from 'three';
3
14
  import { Sticker } from './sticker';
4
15
  import { SVGLoader } from 'three/examples/jsm/Addons.js';
16
+ import { Faces } from '../core';
17
+ /** @import {Vector3Like} from 'three' */
18
+ /** @import {Face} from "../core" */
5
19
 
6
- /** @typedef {{ positon: import('three').Vector3Like, rotation: import('three').Vector3Like }} CornerPieceUserData */
20
+ /** @typedef {{ positon: Vector3Like, rotation: Vector3Like }} CornerPieceUserData */
7
21
  /**
8
22
  * @param {Material} frontMaterial
9
23
  * @param {Material} rightMaterial
@@ -39,6 +53,46 @@ export class CornerPiece extends Object3D {
39
53
  get stickers() {
40
54
  return [this.frontSticker, this.rightSticker, this.topSticker];
41
55
  }
56
+
57
+ /**
58
+ * @param {Face} face
59
+ * @param {string} logoPath
60
+ */
61
+ addLogo(face, logoPath) {
62
+ this.removeLogo();
63
+ const material = new MeshStandardMaterial({
64
+ transparent: true,
65
+ color: 'white',
66
+ metalness: 0,
67
+ roughness: 0.4,
68
+ });
69
+ const mesh = new Mesh(new PlaneGeometry(0.9, 0.9), material);
70
+ if (face === Faces.U) {
71
+ mesh.position.set(0, 0.54, 0);
72
+ mesh.rotation.set(-Math.PI / 2, 0, -Math.PI / 2);
73
+ } else if (face === Faces.F) {
74
+ mesh.position.set(0, 0, 0.54);
75
+ } else if (face === Faces.R) {
76
+ mesh.position.set(0.54, 0, 0);
77
+ mesh.rotation.set(Math.PI / 2, Math.PI / 2, 0);
78
+ }
79
+ this.logo = mesh;
80
+ this.add(mesh);
81
+ const texture = new TextureLoader().load(logoPath, (texture) => {
82
+ texture.colorSpace = SRGBColorSpace;
83
+ material.map = texture;
84
+ material.needsUpdate = true;
85
+ texture.anisotropy = 16;
86
+ });
87
+ }
88
+
89
+ removeLogo() {
90
+ if (!this.logo) return;
91
+ this.remove(this.logo);
92
+ this.logo.material.map?.dispose();
93
+ this.logo.material.dispose();
94
+ this.logo = null;
95
+ }
42
96
  }
43
97
 
44
98
  const loader = new SVGLoader();
@@ -0,0 +1,87 @@
1
+ // @ts-check
2
+ import { CubeTypes, Faces } from '../core';
3
+ /** @import {CubeType, Face} from '../core' */
4
+ /** @import {ColorRepresentation} from 'three' */
5
+
6
+ /**
7
+ * @typedef CubeConfig
8
+ * @property {number[]} layers
9
+ * @property {number} pieceSize
10
+ * @property {number} coreSize
11
+ * @property {number} outerLayerMultiplier
12
+ */
13
+
14
+ /**
15
+ * @param {CubeType} cubeType
16
+ * @return {CubeConfig}
17
+ */
18
+ export function getCubeConfig(cubeType) {
19
+ switch (cubeType) {
20
+ case CubeTypes.Two:
21
+ return {
22
+ layers: [-1, 1],
23
+ pieceSize: 2,
24
+ coreSize: 1.7,
25
+ outerLayerMultiplier: 1,
26
+ };
27
+ break;
28
+ case CubeTypes.Three:
29
+ return {
30
+ layers: [-1, 0, 1],
31
+ pieceSize: 1,
32
+ coreSize: 1.32,
33
+ outerLayerMultiplier: 1,
34
+ };
35
+ case CubeTypes.Four:
36
+ return {
37
+ layers: [-1, -1 / 3, 1 / 3, 1],
38
+ pieceSize: 2 / 3,
39
+ coreSize: 1.25,
40
+ outerLayerMultiplier: 1.1,
41
+ };
42
+ case CubeTypes.Five:
43
+ return {
44
+ layers: [-1, -1 / 2, 0, 1 / 2, 1],
45
+ pieceSize: 1 / 2,
46
+ coreSize: 1.2,
47
+ outerLayerMultiplier: 1.2,
48
+ };
49
+ case CubeTypes.Six:
50
+ return {
51
+ layers: [-1, -3 / 5, -1 / 5, 1 / 5, 3 / 5, 1],
52
+ pieceSize: 2 / 5,
53
+ coreSize: 1.18,
54
+ outerLayerMultiplier: 1.3,
55
+ };
56
+ case CubeTypes.Seven:
57
+ return {
58
+ layers: [-1, -2 / 3, -1 / 3, 0, 1 / 3, 2 / 3, 1],
59
+ pieceSize: 1 / 3,
60
+ coreSize: 1.16,
61
+ outerLayerMultiplier: 1.35,
62
+ };
63
+ default:
64
+ throw new Error(`Unsupported cube type: ${cubeType}`);
65
+ }
66
+ }
67
+
68
+ export const FaceColors = {
69
+ [Faces.B]: 'blue',
70
+ [Faces.D]: 'yellow',
71
+ [Faces.F]: '#2cbf13',
72
+ [Faces.L]: '#fc9a05',
73
+ [Faces.R]: 'red',
74
+ [Faces.U]: 'white',
75
+ };
76
+
77
+ /**
78
+ * @param {ColorRepresentation} color
79
+ * @return {Face}
80
+ * */
81
+ export const ColorToFace = (color) => {
82
+ const face = Object.values(Faces).find((face) => FaceColors[face] === color);
83
+ if (!face) {
84
+ throw new Error(`Invalid color: ${color}`);
85
+ }
86
+ return face;
87
+ };
@@ -0,0 +1,30 @@
1
+ // @ts-check
2
+ import { CubeTypes } from '../core';
3
+ /** @import {CubeType} from '../core' */
4
+
5
+ /**
6
+ * @typedef RubiksCube3DSettingsOptions
7
+ * @property {CubeType} [cubeType]
8
+ * @property {number} [pieceGap]
9
+ * @property {number} [animationSpeedMs]
10
+ * @property {gsap.EaseString | gsap.EaseFunction} [animationStyle]
11
+ * @property {string | null} [logo]
12
+ */
13
+
14
+ export default class RubiksCube3DSettings {
15
+ /**
16
+ * @param {RubiksCube3DSettingsOptions} [options]
17
+ */
18
+ constructor(options = {}) {
19
+ /** @type {CubeType} */
20
+ this.cubeType = options.cubeType ?? CubeTypes.Three;
21
+ /** @type {number} */
22
+ this.pieceGap = options.pieceGap ?? 1.04;
23
+ /** @type {number} */
24
+ this.animationSpeedMs = options.animationSpeedMs ?? 150;
25
+ /** @type {gsap.EaseString | gsap.EaseFunction} */
26
+ this.animationStyle = options.animationStyle ?? 'sine';
27
+ /** @type {string | null} */
28
+ this.logo = options.logo ?? null;
29
+ }
30
+ }
@@ -2,8 +2,9 @@
2
2
  import { BoxGeometry, ExtrudeGeometry, Mesh, MeshBasicMaterial, Object3D } from 'three';
3
3
  import { SVGLoader } from 'three/examples/jsm/Addons.js';
4
4
  import { Sticker } from './sticker';
5
+ /** @import {Vector3Like} from 'three' */
5
6
 
6
- /** @typedef {{ positon: import('three').Vector3Like, rotation: import('three').Vector3Like }} EdgePieceUserData*/
7
+ /** @typedef {{ positon: Vector3Like, rotation: Vector3Like }} EdgePieceUserData*/
7
8
 
8
9
  export class EdgePiece extends Object3D {
9
10
  constructor() {
@@ -0,0 +1,3 @@
1
+ import RubiksCube3D from './rubiksCube3D';
2
+ import RubiksCube3DSettings from './cubeSettings';
3
+ export { RubiksCube3D, RubiksCube3DSettings };