@houstonp/rubiks-cube 1.5.2 → 2.1.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 (51) hide show
  1. package/README.md +280 -170
  2. package/package.json +33 -3
  3. package/src/camera/cameraState.js +81 -0
  4. package/src/core.js +447 -0
  5. package/src/cube/animationSlice.js +205 -0
  6. package/src/cube/animationState.js +96 -0
  7. package/src/cube/cubeSettings.js +19 -0
  8. package/src/cube/cubeState.js +285 -139
  9. package/src/cube/stickerState.js +188 -0
  10. package/src/debouncer.js +16 -0
  11. package/src/globals.ts +9 -0
  12. package/src/index.js +621 -0
  13. package/src/settings.js +138 -0
  14. package/src/three/centerPiece.js +44 -0
  15. package/src/three/cornerPiece.js +60 -0
  16. package/src/three/cube.js +492 -0
  17. package/src/three/edgePiece.js +50 -0
  18. package/src/three/sticker.js +37 -0
  19. package/tests/common.js +27 -0
  20. package/tests/cube.five.test.js +126 -0
  21. package/tests/cube.four.test.js +126 -0
  22. package/tests/cube.seven.test.js +126 -0
  23. package/tests/cube.six.test.js +126 -0
  24. package/tests/cube.three.test.js +151 -0
  25. package/tests/cube.two.test.js +125 -0
  26. package/tests/setup.js +36 -0
  27. package/types/camera/cameraState.d.ts +19 -0
  28. package/types/core.d.ts +454 -0
  29. package/types/cube/animationSlice.d.ts +26 -0
  30. package/types/cube/animationState.d.ts +41 -0
  31. package/types/cube/cubeSettings.d.ts +17 -0
  32. package/types/cube/cubeState.d.ts +47 -0
  33. package/types/cube/stickerState.d.ts +21 -0
  34. package/types/debouncer.d.ts +13 -0
  35. package/types/globals.d.ts +7 -0
  36. package/types/index.d.ts +87 -0
  37. package/types/settings.d.ts +38 -0
  38. package/types/three/centerPiece.d.ts +15 -0
  39. package/types/three/cornerPiece.d.ts +24 -0
  40. package/types/three/cube.d.ts +130 -0
  41. package/types/three/edgePiece.d.ts +16 -0
  42. package/types/three/sticker.d.ts +15 -0
  43. package/.prettierrc +0 -7
  44. package/index.js +0 -274
  45. package/src/cube/cube.js +0 -276
  46. package/src/cube/cubeRotation.js +0 -63
  47. package/src/threejs/materials.js +0 -42
  48. package/src/threejs/pieces.js +0 -103
  49. package/src/threejs/stickers.js +0 -48
  50. package/src/utils/debouncer.js +0 -7
  51. package/src/utils/rotation.js +0 -53
@@ -0,0 +1,138 @@
1
+ // @ts-check
2
+ import { AnimationStyles, CubeTypes } from './core';
3
+ const defaultSettings = {
4
+ cubeType: CubeTypes.Seven,
5
+ animationSpeedMs: 100,
6
+ /** @type {import('./core').AnimationStyle} */
7
+ animationStyle: 'fixed',
8
+ pieceGap: 1.04,
9
+ cameraSpeedMs: 100,
10
+ cameraRadius: 5,
11
+ cameraPeekAngleHorizontal: 0.6,
12
+ cameraPeekAngleVertical: 0.6,
13
+ cameraFieldOfView: 75,
14
+ };
15
+ const minGap = 1;
16
+ const minRadius = 4;
17
+ const minFieldOfView = 30;
18
+ const maxFieldOfView = 100;
19
+
20
+ export default class Settings {
21
+ constructor() {
22
+ /** @type {import("./core").CubeType} */
23
+ this.cubeType = defaultSettings.cubeType;
24
+ /** @type {number} */
25
+ this.pieceGap = defaultSettings.pieceGap;
26
+ /** @type {number} */
27
+ this.animationSpeedMs = defaultSettings.animationSpeedMs;
28
+ /** @type {import("./core").AnimationStyle} */
29
+ this.animationStyle = defaultSettings.animationStyle;
30
+ /** @type {number} */
31
+ this.cameraSpeedMs = defaultSettings.cameraSpeedMs;
32
+ /** @type {number} */
33
+ this.cameraRadius = defaultSettings.cameraRadius;
34
+ /** @type {number} */
35
+ this.cameraFieldOfView = defaultSettings.cameraFieldOfView;
36
+ /** @type {number} */
37
+ this.cameraPeekAngleHorizontal = defaultSettings.cameraPeekAngleHorizontal;
38
+ /** @type {number} */
39
+ this.cameraPeekAngleVertical = defaultSettings.cameraPeekAngleVertical;
40
+ }
41
+
42
+ /** @param {any} value */
43
+ setCubeType(value) {
44
+ if (value && Object.values(CubeTypes).includes(value)) {
45
+ const cubeType = /** @type {import('./core').CubeType} */ (value);
46
+ this.cubeType = cubeType;
47
+ return;
48
+ }
49
+ console.warn(`Invalid cube type value. Accepted Values are [${Object.values(CubeTypes).join(', ')}] Value is ${value}`);
50
+ }
51
+
52
+ /** @param {string | null} value*/
53
+ setPieceGap(value) {
54
+ const gap = Number(value);
55
+ if (gap >= minGap && value != null) {
56
+ this.pieceGap = gap;
57
+ return;
58
+ }
59
+ console.warn(`Invalid pieceGap value. Min is ${minGap}. Value is ${value}`);
60
+ }
61
+
62
+ /** @param {string | null} value in ms */
63
+ setAnimationSpeed(value) {
64
+ var speed = Number(value);
65
+ if (speed >= 0 && value != null) {
66
+ this.animationSpeedMs = speed;
67
+ return;
68
+ }
69
+ console.warn(`Invalid animation speed value. Min is 0. Value is ${value}`);
70
+ }
71
+
72
+ /** @param {any} value */
73
+ setAnimationStyle(value) {
74
+ if (value && Object.values(AnimationStyles).includes(value)) {
75
+ const validStyle = /** @type {import("./core").AnimationStyle} */ (value);
76
+ this.animationStyle = validStyle;
77
+ return;
78
+ }
79
+ console.warn(`Invalid animation style value. Accepted Values are [${Object.values(AnimationStyles).join(', ')}] Value is ${value}`);
80
+ }
81
+
82
+ /** @param {string | null} value in ms */
83
+ setCameraSpeed(value) {
84
+ var speed = Number(value);
85
+ if (speed >= 0 && value != null) {
86
+ this.cameraSpeedMs = speed;
87
+ return;
88
+ }
89
+ console.warn(`Invalid camera speed value. Min is 0. Value is ${value}`);
90
+ }
91
+
92
+ /** @param {string | null} value */
93
+ setCameraRadius(value) {
94
+ var radius = Number(value);
95
+ if (radius >= minRadius && value != null) {
96
+ this.cameraRadius = radius;
97
+ return;
98
+ }
99
+ console.warn(`Invalid camera radius value. Min is ${radius}. Value is ${value}`);
100
+ }
101
+
102
+ /** @param {string | null} value in ms */
103
+ setCameraPeekAngleHorizontal(value) {
104
+ var angle = Number(value);
105
+ if (angle >= 0 && angle <= 1 && value != null) {
106
+ this.cameraPeekAngleHorizontal = angle;
107
+ return;
108
+ }
109
+ console.warn(`Invalid camera peek angle horizontal value. Min is 0, Max is 1. Value is ${value}`);
110
+ }
111
+
112
+ /** @param {string | null} value in ms */
113
+ setCameraPeekAngleVertical(value) {
114
+ var angle = Number(value);
115
+ if (angle >= 0 && angle <= 1 && value != null) {
116
+ this.cameraPeekAngleVertical = angle;
117
+ return;
118
+ }
119
+ console.warn(`Invalid camera peek angle vertical value. Min is 0, Max is 1. Value is ${value}`);
120
+ }
121
+
122
+ /** @param {string | null} value in ms */
123
+ setCameraFieldOfView(value) {
124
+ var fov = Number(value);
125
+ if (fov < minFieldOfView && value != null) {
126
+ console.warn(`Invalid camera FOV value. Min is ${minFieldOfView} Max is ${maxFieldOfView}. Value is ${value} which is below the minimum.`);
127
+ return;
128
+ }
129
+ if (fov > maxFieldOfView && value != null) {
130
+ console.warn(`Invalid camera FOV value. Min is ${minFieldOfView} Max is ${maxFieldOfView}. Value is ${value} which is aboe the maximum.`);
131
+ return;
132
+ }
133
+ if (value == null) {
134
+ console.warn(`Invalid camera FOV value. Min is ${minFieldOfView} Max is ${maxFieldOfView}. Value is ${value}.`);
135
+ }
136
+ this.cameraFieldOfView = fov;
137
+ }
138
+ }
@@ -0,0 +1,44 @@
1
+ // @ts-check
2
+ import { BoxGeometry, ExtrudeGeometry, Mesh, MeshBasicMaterial, Object3D } from 'three';
3
+ import { SVGLoader } from 'three/examples/jsm/Addons.js';
4
+ import { Sticker } from './sticker';
5
+
6
+ /** @typedef {{ positon: import('three').Vector3Like, rotation: import('three').Vector3Like }} CenterPieceUserData */
7
+
8
+ export class CenterPiece extends Object3D {
9
+ constructor() {
10
+ super();
11
+ const boxGeom = new BoxGeometry(1, 1, 1);
12
+ const boxMesh = new Mesh(boxGeom, new MeshBasicMaterial({ color: 'black' }));
13
+ this.add(boxMesh);
14
+ /** @type {CenterPieceUserData} */
15
+ this.userData = { position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 } };
16
+
17
+ this.frontSticker = new CenterSticker();
18
+ this.frontSticker.position.set(0, 0, 0.5);
19
+ this.frontSticker.rotation.set(0, 0, 0);
20
+ this.add(this.frontSticker);
21
+ }
22
+
23
+ get stickers() {
24
+ return [this.frontSticker];
25
+ }
26
+ }
27
+
28
+ const loader = new SVGLoader();
29
+ const centerSVG = loader.parse(`
30
+ <svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
31
+ <path d="M 120 0 L 380 0 C 450 0 500 50 500 120 L 500 380 C 500 450 450 500 380 500 L 120 500 C 50 500 0 450 0 380 L 0 120 C 0 50 50 0 120 0 Z"></path>
32
+ </svg>
33
+ `);
34
+ const centerGeometry = new ExtrudeGeometry(SVGLoader.createShapes(centerSVG.paths[0])[0], {
35
+ depth: 15,
36
+ })
37
+ .scale(0.002, 0.002, 0.002)
38
+ .translate(-0.5, -0.5, 0);
39
+
40
+ export class CenterSticker extends Sticker {
41
+ constructor() {
42
+ super(centerGeometry);
43
+ }
44
+ }
@@ -0,0 +1,60 @@
1
+ /// @ts-check
2
+ import { BoxGeometry, ExtrudeGeometry, Material, Mesh, MeshBasicMaterial, Object3D } from 'three';
3
+ import { Sticker } from './sticker';
4
+ import { SVGLoader } from 'three/examples/jsm/Addons.js';
5
+
6
+ /** @typedef {{ positon: import('three').Vector3Like, rotation: import('three').Vector3Like }} CornerPieceUserData */
7
+ /**
8
+ * @param {Material} frontMaterial
9
+ * @param {Material} rightMaterial
10
+ * @param {Material} topMaterial
11
+ * @param {Material} coreMaterial
12
+ * @returns {Group}
13
+ */
14
+ export class CornerPiece extends Object3D {
15
+ constructor() {
16
+ super();
17
+ const boxGeom = new BoxGeometry(1, 1, 1);
18
+ const boxMesh = new Mesh(boxGeom, new MeshBasicMaterial({ color: 'black' }));
19
+ this.add(boxMesh);
20
+ /** @type {CornerPieceUserData} */
21
+ this.userData = { position: { x: 0, y: 0, z: 0 }, rotation: { x: 0, y: 0, z: 0 } };
22
+
23
+ this.frontSticker = new CornerSticker();
24
+ this.frontSticker.position.set(0, 0, 0.5);
25
+ this.frontSticker.rotation.set(0, 0, 0);
26
+ this.add(this.frontSticker);
27
+
28
+ this.rightSticker = new CornerSticker();
29
+ this.rightSticker.position.set(0.5, 0, 0);
30
+ this.rightSticker.rotation.set(Math.PI / 2, Math.PI / 2, 0);
31
+ this.add(this.rightSticker);
32
+
33
+ this.topSticker = new CornerSticker();
34
+ this.topSticker.position.set(0, 0.5, 0);
35
+ this.topSticker.rotation.set(-Math.PI / 2, 0, -Math.PI / 2);
36
+ this.add(this.topSticker);
37
+ }
38
+
39
+ get stickers() {
40
+ return [this.frontSticker, this.rightSticker, this.topSticker];
41
+ }
42
+ }
43
+
44
+ const loader = new SVGLoader();
45
+ const cornerSVG = loader.parse(`
46
+ <svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
47
+ <path d="M 25 0 H 500 V 500 H 0 V 25 A 25 25 0 0 1 25 0 Z" bx:shape="rect 0 0 500 500 25 0 0 0 1@a864c1ee"/>
48
+ </svg>
49
+ `);
50
+ const cornerGeometry = new ExtrudeGeometry(SVGLoader.createShapes(cornerSVG.paths[0])[0], {
51
+ depth: 15,
52
+ })
53
+ .scale(0.002, 0.002, 0.002)
54
+ .translate(-0.5, -0.5, 0);
55
+
56
+ export class CornerSticker extends Sticker {
57
+ constructor() {
58
+ super(cornerGeometry);
59
+ }
60
+ }