@houstonp/rubiks-cube 1.1.1 → 1.2.1

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.
@@ -0,0 +1,194 @@
1
+ import { Group, Vector3 } from 'three';
2
+ import { createCoreMesh } from '../threejs/pieces';
3
+ import { createCubeState } from './cubeState';
4
+ import { CubeRotation } from './cubeRotation';
5
+
6
+ const minimumGap = 1;
7
+
8
+ export default class Cube {
9
+ /**
10
+ * @param {{style: "exponential" | "next" | "fixed", speed: number, gap: number}} params
11
+ */
12
+ constructor({ gap, speed, style }) {
13
+ /** @type {number} */
14
+ this.gap = gap < minimumGap ? minimumGap : gap;
15
+ /** @type {Group} */
16
+ this.group = new Group();
17
+ /** @type {Group} */
18
+ this.rotationGroup = new Group();
19
+ /** @type {CubeRotation[]} */
20
+ this.rotationQueue = [];
21
+ /** @type {CubeRotation | undefined} */
22
+ this.currentRotation = undefined;
23
+ /** @type {number} */
24
+ this.animationSpeed = speed;
25
+ /** @type {"exponential" | "next" | "fixed"} */
26
+ this.animationStyle = style;
27
+
28
+ const core = createCoreMesh();
29
+ core.userData = {
30
+ position: { x: 0, y: 0, z: 0 },
31
+ rotation: { x: 0, y: 0, z: 0 },
32
+ initialPosition: { x: 0, y: 0, z: 0 },
33
+ initialRotation: { x: 0, y: 0, z: 0 },
34
+ type: 'core',
35
+ };
36
+ this.group.add(core);
37
+
38
+ for (const piece of createCubeState()) {
39
+ var pieceGroup = piece.group;
40
+ pieceGroup.position.set(piece.position.x * this.gap, piece.position.y * this.gap, piece.position.z * this.gap);
41
+ pieceGroup.rotation.set(piece.rotation.x, piece.rotation.y, piece.rotation.z);
42
+ pieceGroup.userData = {
43
+ position: Object.assign({}, piece.position),
44
+ rotation: Object.assign({}, piece.rotation),
45
+ initialPosition: Object.assign({}, piece.position),
46
+ initialRotation: Object.assign({}, piece.rotation),
47
+ type: piece.type,
48
+ };
49
+ this.group.add(pieceGroup);
50
+ }
51
+ }
52
+
53
+ update() {
54
+ if (this.currentRotation === undefined) {
55
+ this.currentRotation = this.rotationQueue.shift();
56
+ if (this.currentRotation === undefined) return;
57
+ this.rotationGroup.add(...this.getRotationLayer(this.currentRotation.rotation));
58
+ this.currentRotation.initialise();
59
+ }
60
+
61
+ if (this.currentRotation.status === 'complete') {
62
+ this.clearRotationGroup();
63
+ this.currentRotation.dispose();
64
+ this.currentRotation = this.rotationQueue.shift();
65
+ if (this.currentRotation === undefined) return;
66
+ this.rotationGroup.add(...this.getRotationLayer(this.currentRotation.rotation));
67
+ this.currentRotation.initialise();
68
+ }
69
+
70
+ this.currentRotation.update(this.rotationGroup, this.getRotationSpeed());
71
+ }
72
+
73
+ getRotationSpeed() {
74
+ if (this.animationStyle == 'exponential') {
75
+ return this.animationSpeed / 2 ** this.rotationQueue.length;
76
+ }
77
+ if (this.animationStyle == 'next') {
78
+ return this.rotationQueue.length > 0 ? 0 : this.animationSpeed;
79
+ }
80
+ return this.animationSpeed;
81
+ }
82
+
83
+ reset() {
84
+ this.rotationQueue = [];
85
+ if (this.currentRotation) {
86
+ this.currentRotation.update(this.rotationGroup, 0);
87
+ this.clearRotationGroup();
88
+ this.currentRotation.dispose();
89
+ this.currentRotation = undefined;
90
+ }
91
+ this.group.children.forEach((piece) => {
92
+ const { x, y, z } = piece.userData.initialPosition;
93
+ const { x: u, y: v, z: w } = piece.userData.initialRotation;
94
+ piece.position.set(x * this.gap, y * this.gap, z * this.gap);
95
+ piece.rotation.set(u, v, w);
96
+ piece.userData.position.x = x;
97
+ piece.userData.position.y = y;
98
+ piece.userData.position.z = z;
99
+ piece.userData.rotation.x = u;
100
+ piece.userData.rotation.y = v;
101
+ piece.userData.rotation.z = w;
102
+ });
103
+ }
104
+
105
+ clearRotationGroup() {
106
+ if (this.currentRotation.status != 'complete') {
107
+ throw Error('cannot clear rotation group while rotating');
108
+ }
109
+ this.rotationGroup.children.forEach((piece) => {
110
+ piece.getWorldPosition(piece.position);
111
+ piece.getWorldQuaternion(piece.quaternion);
112
+ var x = Math.round(piece.position.x);
113
+ var y = Math.round(piece.position.y);
114
+ var z = Math.round(piece.position.z);
115
+ piece.userData.position.x = Math.abs(x) > 1 ? Math.sign(x) : x;
116
+ piece.userData.position.y = Math.abs(y) > 1 ? Math.sign(y) : y;
117
+ piece.userData.position.z = Math.abs(z) > 1 ? Math.sign(z) : z;
118
+ piece.userData.rotation.x = piece.rotation.x;
119
+ piece.userData.rotation.y = piece.rotation.y;
120
+ piece.userData.rotation.z = piece.rotation.z;
121
+ });
122
+ this.group.add(...this.rotationGroup.children);
123
+ this.rotationGroup.rotation.set(0, 0, 0);
124
+ }
125
+
126
+ /**
127
+ * @param {{axis: "x"|"y"|"z", layers: (-1|0|1)[], direction: 1|-1|2|-2}} input
128
+ */
129
+ rotate(input) {
130
+ this.rotationQueue.push(new CubeRotation(input));
131
+ }
132
+
133
+ /**
134
+ * @param {{axis: "x"|"y"|"z", layers: (-1|0|1)[], direction: 1|-1|2|-2}}
135
+ * @returns {Object3D[]}
136
+ */
137
+ getRotationLayer({ axis, layers, direction }) {
138
+ if (layers.length === 0) {
139
+ return [...this.group.children];
140
+ }
141
+ return this.group.children.filter((piece) => {
142
+ if (axis === 'x') {
143
+ return layers.includes(Math.round(piece.userData.position.x));
144
+ } else if (axis === 'y') {
145
+ return layers.includes(Math.round(piece.userData.position.y));
146
+ } else if (axis === 'z') {
147
+ return layers.includes(Math.round(piece.userData.position.z));
148
+ }
149
+ return false;
150
+ });
151
+ }
152
+
153
+ getStickerState() {
154
+ const state = {
155
+ up: [[], [], []],
156
+ down: [[], [], []],
157
+ front: [[], [], []],
158
+ back: [[], [], []],
159
+ left: [[], [], []],
160
+ right: [[], [], []],
161
+ };
162
+ this.group.children.forEach((piece) => {
163
+ if (piece.userData.type === 'core') {
164
+ return;
165
+ }
166
+ piece.children.forEach((mesh) => {
167
+ if (mesh.userData.type === 'sticker') {
168
+ const piecepos = new Vector3();
169
+ piecepos.copy(piece.userData.position);
170
+ piecepos.round();
171
+ const stickerpos = new Vector3();
172
+ mesh.getWorldPosition(stickerpos);
173
+ stickerpos.sub(piecepos);
174
+ stickerpos.multiplyScalar(2);
175
+ stickerpos.round();
176
+ if (stickerpos.x === 1) {
177
+ state.right[1 - Math.round(piecepos.y)][1 - Math.round(piecepos.z)] = mesh.material.userData.face;
178
+ } else if (stickerpos.x === -1) {
179
+ state.left[1 - Math.round(piecepos.y)][1 + Math.round(piecepos.z)] = mesh.material.userData.face;
180
+ } else if (stickerpos.y === 1) {
181
+ state.up[1 + Math.round(piecepos.z)][1 + Math.round(piecepos.x)] = mesh.material.userData.face;
182
+ } else if (stickerpos.y === -1) {
183
+ state.down[1 - Math.round(piecepos.z)][1 + Math.round(piecepos.x)] = mesh.material.userData.face;
184
+ } else if (stickerpos.z === 1) {
185
+ state.front[1 - Math.round(piecepos.y)][1 + Math.round(piecepos.x)] = mesh.material.userData.face;
186
+ } else if (stickerpos.z === -1) {
187
+ state.back[1 - Math.round(piecepos.y)][1 - Math.round(piecepos.x)] = mesh.material.userData.face;
188
+ }
189
+ }
190
+ });
191
+ });
192
+ return state;
193
+ }
194
+ }
@@ -0,0 +1,60 @@
1
+ import { Vector3, Group } from 'three';
2
+
3
+ export class CubeRotation {
4
+ /**
5
+ * @param {{axis: "x"|"y"|"z", layers: (-1|0|1)[], direction: 1|-1|2|-2}} input
6
+ */
7
+ constructor(rotation) {
8
+ /** @type {{axis: "x"|"y"|"z", layers: (-1|0|1)[], direction: 1|-1|2|-2}} */
9
+ this.rotation = rotation;
10
+ /** @type {"pending" | "initialised" | "complete" | "disposed"} */
11
+ this.status = 'pending';
12
+ /** @type {number} */
13
+ this._lastUpdatedTimeMs = undefined;
14
+ this._startTimeMs = undefined;
15
+ /** @type {number} */
16
+ this._rotationPercentage = 0;
17
+ }
18
+
19
+ initialise() {
20
+ this._lastUpdatedTimeMs = performance.now();
21
+ this._startTimeMs = this._lastUpdatedTimeMs;
22
+ this.status = 'initialised';
23
+ }
24
+
25
+ dispose() {
26
+ this.status = 'disposed';
27
+ }
28
+
29
+ /**
30
+ *
31
+ * @param {Group} rotationGroup
32
+ * @param {number} speedMs
33
+ */
34
+ update(rotationGroup, speedMs) {
35
+ var intervalMs = performance.now() - this._lastUpdatedTimeMs;
36
+ this._lastUpdatedTimeMs = performance.now();
37
+
38
+ var increment = 100 - this._rotationPercentage;
39
+ if (speedMs != 0) {
40
+ var potentialIncrement = (intervalMs / speedMs) * 100;
41
+ if (potentialIncrement + this._rotationPercentage < 100) {
42
+ increment = potentialIncrement;
43
+ }
44
+ }
45
+ const rotationIncrement = (Math.abs(this.rotation.direction) * ((increment / 100) * Math.PI)) / 2;
46
+ this._rotationPercentage += increment;
47
+ rotationGroup.rotateOnWorldAxis(
48
+ new Vector3(
49
+ this.rotation.axis === 'x' ? this.rotation.direction : 0,
50
+ this.rotation.axis === 'y' ? this.rotation.direction : 0,
51
+ this.rotation.axis === 'z' ? this.rotation.direction : 0,
52
+ ).normalize(),
53
+ rotationIncrement,
54
+ );
55
+
56
+ if (this._rotationPercentage >= 100) {
57
+ this.status = 'complete';
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,191 @@
1
+ import { Group } from 'three';
2
+ import Materials from '../threejs/materials';
3
+ import { createCornerGroup, createEdgeGroup, createCenterGroup } from '../threejs/pieces';
4
+
5
+ /**
6
+ * @typedef {{x: number,y: number,z: number}} vector
7
+ */
8
+
9
+ /**
10
+ * @typedef {{position: vector, rotation: vector, type: "corner" | "edge" | "center", group: Group}} state
11
+ */
12
+
13
+ /**
14
+ * @return {state[]}
15
+ */
16
+ const corners = () => [
17
+ {
18
+ position: { x: 1, y: 1, z: 1 },
19
+ rotation: { x: 0, y: 0, z: 0 },
20
+ type: 'corner',
21
+ group: createCornerGroup(Materials.front, Materials.right, Materials.up, Materials.core),
22
+ },
23
+ {
24
+ position: { x: 1, y: 1, z: -1 },
25
+ rotation: { x: 0, y: Math.PI / 2, z: 0 },
26
+ type: 'corner',
27
+ group: createCornerGroup(Materials.right, Materials.back, Materials.up, Materials.core),
28
+ },
29
+ {
30
+ position: { x: 1, y: -1, z: 1 },
31
+ rotation: { x: 0, y: Math.PI / 2, z: Math.PI },
32
+ type: 'corner',
33
+ group: createCornerGroup(Materials.right, Materials.front, Materials.down, Materials.core),
34
+ },
35
+ {
36
+ position: { x: 1, y: -1, z: -1 },
37
+ rotation: { x: 0, y: Math.PI, z: Math.PI },
38
+ type: 'corner',
39
+ group: createCornerGroup(Materials.back, Materials.right, Materials.down, Materials.core),
40
+ },
41
+ {
42
+ position: { x: -1, y: 1, z: 1 },
43
+ rotation: { x: 0, y: -Math.PI / 2, z: 0 },
44
+ type: 'corner',
45
+ group: createCornerGroup(Materials.left, Materials.front, Materials.up, Materials.core),
46
+ },
47
+ {
48
+ position: { x: -1, y: 1, z: -1 },
49
+ rotation: { x: 0, y: Math.PI, z: 0 },
50
+ type: 'corner',
51
+ group: createCornerGroup(Materials.back, Materials.left, Materials.up, Materials.core),
52
+ },
53
+ {
54
+ position: { x: -1, y: -1, z: 1 },
55
+ rotation: { x: 0, y: 0, z: Math.PI },
56
+ type: 'corner',
57
+ group: createCornerGroup(Materials.front, Materials.left, Materials.down, Materials.core),
58
+ },
59
+ {
60
+ position: { x: -1, y: -1, z: -1 },
61
+ rotation: { x: 0, y: -Math.PI / 2, z: Math.PI },
62
+ type: 'corner',
63
+ group: createCornerGroup(Materials.left, Materials.back, Materials.down, Materials.core),
64
+ },
65
+ ];
66
+
67
+ /**
68
+ * @return {state[]}
69
+ */
70
+ const edges = () => [
71
+ {
72
+ position: { x: 1, y: 1, z: 0 },
73
+ rotation: { x: 0, y: Math.PI / 2, z: 0 },
74
+ type: 'edge',
75
+ group: createEdgeGroup(Materials.right, Materials.up, Materials.core),
76
+ },
77
+ {
78
+ position: { x: 1, y: 0, z: 1 },
79
+ rotation: { x: 0, y: 0, z: -Math.PI / 2 },
80
+ type: 'edge',
81
+ group: createEdgeGroup(Materials.front, Materials.right, Materials.core),
82
+ },
83
+ {
84
+ position: { x: 1, y: 0, z: -1 },
85
+ rotation: { x: 0, y: Math.PI / 2, z: -Math.PI / 2 },
86
+ type: 'edge',
87
+ group: createEdgeGroup(Materials.right, Materials.back, Materials.core),
88
+ },
89
+ {
90
+ position: { x: 1, y: -1, z: 0 },
91
+ rotation: { x: Math.PI, y: Math.PI / 2, z: 0 },
92
+ type: 'edge',
93
+ group: createEdgeGroup(Materials.right, Materials.down, Materials.core),
94
+ },
95
+ {
96
+ position: { x: 0, y: 1, z: 1 },
97
+ rotation: { x: 0, y: 0, z: 0 },
98
+ type: 'edge',
99
+ group: createEdgeGroup(Materials.front, Materials.up, Materials.core),
100
+ },
101
+ {
102
+ position: { x: 0, y: 1, z: -1 },
103
+ rotation: { x: -Math.PI / 2, y: 0, z: 0 },
104
+ type: 'edge',
105
+ group: createEdgeGroup(Materials.up, Materials.back, Materials.core),
106
+ },
107
+ {
108
+ position: { x: 0, y: -1, z: 1 },
109
+ rotation: { x: Math.PI / 2, y: 0, z: 0 },
110
+ type: 'edge',
111
+ group: createEdgeGroup(Materials.down, Materials.front, Materials.core),
112
+ },
113
+ {
114
+ position: { x: 0, y: -1, z: -1 },
115
+ rotation: { x: Math.PI, y: 0, z: 0 },
116
+ type: 'edge',
117
+ group: createEdgeGroup(Materials.back, Materials.down, Materials.core),
118
+ },
119
+ {
120
+ position: { x: -1, y: 1, z: 0 },
121
+ rotation: { x: 0, y: -Math.PI / 2, z: 0 },
122
+ type: 'edge',
123
+ group: createEdgeGroup(Materials.left, Materials.up, Materials.core),
124
+ },
125
+ {
126
+ position: { x: -1, y: 0, z: 1 },
127
+ rotation: { x: 0, y: 0, z: Math.PI / 2 },
128
+ type: 'edge',
129
+ group: createEdgeGroup(Materials.front, Materials.left, Materials.core),
130
+ },
131
+ {
132
+ position: { x: -1, y: 0, z: -1 },
133
+ rotation: { x: 0, y: -Math.PI / 2, z: Math.PI / 2 },
134
+ type: 'edge',
135
+ group: createEdgeGroup(Materials.left, Materials.back, Materials.core),
136
+ },
137
+ {
138
+ position: { x: -1, y: -1, z: 0 },
139
+ rotation: { x: 0, y: -Math.PI / 2, z: Math.PI },
140
+ type: 'edge',
141
+ group: createEdgeGroup(Materials.left, Materials.down, Materials.core),
142
+ },
143
+ ];
144
+
145
+ /**
146
+ * @return {state[]}
147
+ */
148
+ const centers = () => [
149
+ {
150
+ position: { x: 1, y: 0, z: 0 },
151
+ rotation: { x: 0, y: Math.PI / 2, z: 0 },
152
+ type: 'center',
153
+ group: createCenterGroup(Materials.right, Materials.core),
154
+ },
155
+ {
156
+ position: { x: 0, y: 1, z: 0 },
157
+ rotation: { x: -Math.PI / 2, y: 0, z: 0 },
158
+ type: 'center',
159
+ group: createCenterGroup(Materials.up, Materials.core),
160
+ },
161
+ {
162
+ position: { x: 0, y: 0, z: 1 },
163
+ rotation: { x: 0, y: 0, z: 0 },
164
+ type: 'center',
165
+ group: createCenterGroup(Materials.front, Materials.core),
166
+ },
167
+ {
168
+ position: { x: 0, y: 0, z: -1 },
169
+ rotation: { x: 0, y: Math.PI, z: 0 },
170
+ type: 'center',
171
+ group: createCenterGroup(Materials.back, Materials.core),
172
+ },
173
+ {
174
+ position: { x: 0, y: -1, z: 0 },
175
+ rotation: { x: Math.PI / 2, y: 0, z: 0 },
176
+ type: 'center',
177
+ group: createCenterGroup(Materials.down, Materials.core),
178
+ },
179
+ {
180
+ position: { x: -1, y: 0, z: 0 },
181
+ rotation: { x: 0, y: -Math.PI / 2, z: 0 },
182
+ type: 'center',
183
+ group: createCenterGroup(Materials.left, Materials.core),
184
+ },
185
+ ];
186
+
187
+ /**
188
+ * @return {state[]}
189
+ */
190
+ const createCubeState = () => [...corners(), ...edges(), ...centers()];
191
+ export { createCubeState };
@@ -1,42 +1,42 @@
1
- import * as THREE from "three";
1
+ import { MeshStandardMaterial, MeshBasicMaterial } from "three";
2
2
  export default class Materials {
3
- static front = new THREE.MeshStandardMaterial({
3
+ static front = new MeshStandardMaterial({
4
4
  color: "#2cbf13",
5
5
  metalness: 0,
6
6
  roughness: 0.4,
7
7
  userData: { face: "front", color: "green" },
8
8
  });
9
- static back = new THREE.MeshStandardMaterial({
9
+ static back = new MeshStandardMaterial({
10
10
  color: "blue",
11
11
  metalness: 0,
12
12
  roughness: 0.4,
13
13
  userData: { face: "back", color: "blue" },
14
14
  });
15
- static up = new THREE.MeshStandardMaterial({
15
+ static up = new MeshStandardMaterial({
16
16
  color: "white",
17
17
  metalness: 0,
18
18
  roughness: 0.4,
19
19
  userData: { face: "up", color: "white" },
20
20
  });
21
- static down = new THREE.MeshStandardMaterial({
21
+ static down = new MeshStandardMaterial({
22
22
  color: "yellow",
23
23
  metalness: 0,
24
24
  roughness: 0.4,
25
25
  userData: { face: "down", color: "yellow" },
26
26
  });
27
- static left = new THREE.MeshStandardMaterial({
27
+ static left = new MeshStandardMaterial({
28
28
  color: "#fc9a05",
29
29
  metalness: 0,
30
30
  roughness: 0.4,
31
31
  userData: { face: "left", color: "orange" },
32
32
  });
33
- static right = new THREE.MeshStandardMaterial({
33
+ static right = new MeshStandardMaterial({
34
34
  color: "red",
35
35
  metalness: 0,
36
36
  roughness: 0.4,
37
37
  userData: { face: "right", color: "red" },
38
38
  });
39
- static core = new THREE.MeshBasicMaterial({
39
+ static core = new MeshBasicMaterial({
40
40
  color: "black",
41
41
  });
42
42
  }
@@ -0,0 +1,103 @@
1
+ import { Group, BoxGeometry, Mesh, SphereGeometry, Material } from 'three';
2
+ import Stickers from './stickers';
3
+ import Materials from './materials';
4
+
5
+ /**
6
+ * @param {Geometry} sticker
7
+ * @param {Material} frontMaterial
8
+ * @param {Material} rightMaterial
9
+ * @param {Material} topMaterial
10
+ * @param {Material} coreMaterial
11
+ * @returns {Group}
12
+ */
13
+ export function createCornerGroup(frontMaterial, rightMaterial, topMaterial, coreMaterial) {
14
+ const group = new Group();
15
+ const boxGeom = new BoxGeometry(1, 1, 1);
16
+ const boxMesh = new Mesh(boxGeom, coreMaterial);
17
+ boxMesh.userData = { type: 'piece' };
18
+ group.add(boxMesh);
19
+
20
+ // front
21
+ const frontSticker = new Mesh(Stickers.corner, frontMaterial);
22
+ frontSticker.userData = { type: 'sticker' };
23
+ frontSticker.position.set(0, 0, 0.5);
24
+ frontSticker.rotation.set(0, 0, 0);
25
+ group.add(frontSticker);
26
+
27
+ //right
28
+ const rightSticker = new Mesh(Stickers.corner, rightMaterial);
29
+ rightSticker.userData = { type: 'sticker' };
30
+ rightSticker.position.set(0.5, 0, 0);
31
+ rightSticker.rotation.set(Math.PI / 2, Math.PI / 2, 0);
32
+ group.add(rightSticker);
33
+
34
+ //white/yellow
35
+ const topSticker = new Mesh(Stickers.corner, topMaterial);
36
+ topSticker.userData = { type: 'sticker' };
37
+ topSticker.position.set(0, 0.5, 0);
38
+ topSticker.rotation.set(-Math.PI / 2, 0, -Math.PI / 2);
39
+ group.add(topSticker);
40
+
41
+ return group;
42
+ }
43
+
44
+ /**
45
+ * @param {Geometry} sticker
46
+ * @param {Material} frontMaterial
47
+ * @param {Material} topMaterial
48
+ * @param {Material} coreMaterial
49
+ * @returns {Group}
50
+ */
51
+ export function createEdgeGroup(frontMaterial, topMaterial, coreMaterial) {
52
+ const group = new Group();
53
+ const boxGeom = new BoxGeometry(1, 1, 1);
54
+ const boxMesh = new Mesh(boxGeom, coreMaterial);
55
+ boxMesh.userData = { type: 'piece' };
56
+ group.add(boxMesh);
57
+
58
+ // front
59
+ const frontSticker = new Mesh(Stickers.edge, frontMaterial);
60
+ frontSticker.userData = { type: 'sticker' };
61
+ frontSticker.position.set(0, 0, 0.5);
62
+ frontSticker.rotation.set(0, 0, 0);
63
+ group.add(frontSticker);
64
+
65
+ // top
66
+ const topSticker = new Mesh(Stickers.edge, topMaterial);
67
+ topSticker.userData = { type: 'sticker' };
68
+ topSticker.position.set(0, 0.5, 0);
69
+ topSticker.rotation.set(-Math.PI / 2, 0, Math.PI);
70
+ group.add(topSticker);
71
+
72
+ return group;
73
+ }
74
+
75
+ /**
76
+ * @param {Geometry} sticker
77
+ * @param {Material} frontMaterial
78
+ * @param {Material} topMaterial
79
+ * @param {Material} coreMaterial
80
+ * @returns {Group}
81
+ */
82
+ export function createCenterGroup(frontMaterial, coreMaterial) {
83
+ const group = new Group();
84
+ const boxGeom = new BoxGeometry(1, 1, 1);
85
+ const boxMesh = new Mesh(boxGeom, coreMaterial);
86
+ boxMesh.userData = { type: 'piece' };
87
+ group.add(boxMesh);
88
+
89
+ const frontSticker = new Mesh(Stickers.center, frontMaterial);
90
+ frontSticker.userData = { type: 'sticker' };
91
+ frontSticker.position.set(0, 0, 0.5);
92
+ frontSticker.rotation.set(0, 0, 0);
93
+ group.add(frontSticker);
94
+
95
+ return group;
96
+ }
97
+
98
+ /**
99
+ * @returns {Mesh}
100
+ */
101
+ export function createCoreMesh() {
102
+ return new Mesh(new SphereGeometry(1.53), Materials.core);
103
+ }
@@ -1,5 +1,5 @@
1
- import * as THREE from "three";
2
1
  import { SVGLoader } from "three/examples/jsm/Addons.js";
2
+ import { ExtrudeGeometry } from "three";
3
3
 
4
4
  const loader = new SVGLoader();
5
5
  const cornerSVG = loader.parse(`
@@ -19,7 +19,7 @@ const centerSVG = loader.parse(`
19
19
  `);
20
20
 
21
21
  export default class Stickers {
22
- static center = new THREE.ExtrudeGeometry(
22
+ static center = new ExtrudeGeometry(
23
23
  SVGLoader.createShapes(centerSVG.paths[0])[0],
24
24
  {
25
25
  depth: 15,
@@ -28,7 +28,7 @@ export default class Stickers {
28
28
  .scale(0.002, 0.002, 0.002)
29
29
  .translate(-0.5, -0.5, 0);
30
30
 
31
- static edge = new THREE.ExtrudeGeometry(
31
+ static edge = new ExtrudeGeometry(
32
32
  SVGLoader.createShapes(edgeSVG.paths[0])[0],
33
33
  {
34
34
  depth: 15,
@@ -37,7 +37,7 @@ export default class Stickers {
37
37
  .scale(0.002, 0.002, 0.002)
38
38
  .translate(-0.5, -0.5, 0);
39
39
 
40
- static corner = new THREE.ExtrudeGeometry(
40
+ static corner = new ExtrudeGeometry(
41
41
  SVGLoader.createShapes(cornerSVG.paths[0])[0],
42
42
  {
43
43
  depth: 15,
@@ -0,0 +1,7 @@
1
+ export function debounce(f, delay) {
2
+ let timer = 0;
3
+ return function (...args) {
4
+ clearTimeout(timer);
5
+ timer = setTimeout(() => f.apply(this, args), delay);
6
+ };
7
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @param {string} action
3
+ * @returns {{axis: "x"|"y"|"z", layers: (0|1|-1)[], direction: (1|-1|2|-2)}}
4
+ */
5
+ export default function getRotationDetailsFromNotation(action) {
6
+ if (!action) return;
7
+ const reverse = action.includes("'") ? -1 : 1;
8
+ action = action.replace("'", '');
9
+ const multiplier = action.includes('2') ? 2 : 1;
10
+ action = action.replace('2', '');
11
+ if (!action) return;
12
+ const move = action[0];
13
+
14
+ if (move === 'x') {
15
+ return { axis: 'x', layers: [], direction: -reverse * multiplier };
16
+ } else if (move === 'y') {
17
+ return { axis: 'y', layers: [], direction: -reverse * multiplier };
18
+ } else if (move === 'z') {
19
+ return { axis: 'z', layers: [], direction: -reverse * multiplier };
20
+ } else if (move === 'U') {
21
+ return { axis: 'y', layers: [1], direction: -reverse * multiplier };
22
+ } else if (move === 'u') {
23
+ return { axis: 'y', layers: [1, 0], direction: -reverse * multiplier };
24
+ } else if (move === 'R') {
25
+ return { axis: 'x', layers: [1], direction: -reverse * multiplier };
26
+ } else if (move === 'r') {
27
+ return { axis: 'x', layers: [1, 0], direction: -reverse * multiplier };
28
+ } else if (move === 'L') {
29
+ return { axis: 'x', layers: [-1], direction: -reverse * multiplier };
30
+ } else if (move == 'l') {
31
+ return { axis: 'x', layers: [-1, 0], direction: -reverse * multiplier };
32
+ } else if (move === 'D') {
33
+ return { axis: 'y', layers: [-1], direction: -reverse * multiplier };
34
+ } else if (move === 'd') {
35
+ return { axis: 'y', layers: [-1, 0], direction: -reverse * multiplier };
36
+ } else if (move === 'F') {
37
+ return { axis: 'z', layers: [1], direction: -reverse * multiplier };
38
+ } else if (move === 'f') {
39
+ return { axis: 'z', layers: [1, 0], direction: -reverse * multiplier };
40
+ } else if (move === 'B') {
41
+ return { axis: 'z', layers: [-1], direction: -reverse * multiplier };
42
+ } else if (move === 'b') {
43
+ return { axis: 'z', layers: [-1, 0], direction: -reverse * multiplier };
44
+ } else if (move === 'M') {
45
+ return { axis: 'x', layers: [0], direction: -reverse * multiplier };
46
+ } else if (move === 'E') {
47
+ return { axis: 'y', layers: [0], direction: -reverse * multiplier };
48
+ } else if (move === 'S') {
49
+ return { axis: 'z', layers: [0], direction: -reverse * multiplier };
50
+ }
51
+ console.log(`rubiks-cube invalid Action: ${action}`);
52
+ return undefined;
53
+ }