@houstonp/rubiks-cube 1.4.1 → 1.5.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.
- package/README.md +46 -42
- package/index.js +128 -50
- package/package.json +2 -3
- package/src/cube/cube.js +18 -14
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Rubiks Cube Web Component
|
|
2
2
|
|
|
3
|
-
This package is a rubiks cube web component built with threejs. Camera animation smoothing is done with the
|
|
3
|
+
This package is a rubiks cube web component built with threejs. Camera animation smoothing is done with the gsap package.
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
@@ -21,7 +21,7 @@ import '@houstonp/rubiks-cube';
|
|
|
21
21
|
<meta charset="utf-8" />
|
|
22
22
|
</head>
|
|
23
23
|
<body>
|
|
24
|
-
<rubiks-cube animation-speed="1000" animation-style="exponential" piece-gap="1.04" camera-speed="100"> </rubiks-cube>
|
|
24
|
+
<rubiks-cube animation-speed-ms="1000" animation-style="exponential" piece-gap="1.04" camera-speed="100"> </rubiks-cube>
|
|
25
25
|
<script type="module" src="index.js"></script>
|
|
26
26
|
</body>
|
|
27
27
|
</html>
|
|
@@ -29,12 +29,16 @@ import '@houstonp/rubiks-cube';
|
|
|
29
29
|
|
|
30
30
|
## component attributes
|
|
31
31
|
|
|
32
|
-
| attribute
|
|
33
|
-
|
|
|
34
|
-
| animation-speed
|
|
35
|
-
| animation-style
|
|
36
|
-
| piece-gap
|
|
37
|
-
| camera-speed
|
|
32
|
+
| attribute | accepted values | Description |
|
|
33
|
+
| ---------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
34
|
+
| animation-speed-ms | integer greater than or equal to 0 | sets the duration of the animations in milliseconds |
|
|
35
|
+
| animation-style | "exponetial", "next", "fixed", "match" | fixed: fixed animation lengths, next: skips to next animation, exponential: speeds up successive animations, match: matches the speed the frequency of events |
|
|
36
|
+
| piece-gap | greater than 1 | sets the gap between rubiks cube pieces |
|
|
37
|
+
| camera-speed-ms | greater than or equal to 0 | sets the duration of camera animations in milliseconds |
|
|
38
|
+
| camera-radius | greater than or equal to 4 | sets the camera radius |
|
|
39
|
+
| camera-peek-angle-horizontal | decimal between 0 and 1 | sets the horizontal peek angle |
|
|
40
|
+
| camera-peek-angle-vertical | decimal between 0 and 1 | sets the vertical peek angle |
|
|
41
|
+
| camera-field-of-view | integer between 40 and 100 | sets the fielf of view of the camera |
|
|
38
42
|
|
|
39
43
|
## state of the component
|
|
40
44
|
|
|
@@ -156,12 +160,12 @@ var event = new CustomEvent('action', {
|
|
|
156
160
|
|
|
157
161
|
action IDs for camera actions are as follows
|
|
158
162
|
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
-
|
|
163
|
+
- `peek-right` - Camera is moved to the right of the cube so that the right face is visible
|
|
164
|
+
- `peek-left` - Camera is moved to the left of the cube so that the left face is visible
|
|
165
|
+
- `peek-top` - Camera is moved above the cube so that the top face is visible
|
|
166
|
+
- `peek-bottom` - Camera is moved below the cube so that the bottom face is visible
|
|
167
|
+
- `peek-toggle-horizontal` - Camera is moved to the opposite side of the cube in the horizontal plane
|
|
168
|
+
- `peek-toggle-vertical` - Camera is moved to the opposite side of the cube in the vertical plane
|
|
165
169
|
|
|
166
170
|
#### Example
|
|
167
171
|
|
|
@@ -183,15 +187,15 @@ cube.dispatchEvent(event);
|
|
|
183
187
|
|
|
184
188
|
actionIDs for action type "rotation" are as follows
|
|
185
189
|
|
|
186
|
-
-
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
190
|
-
-
|
|
191
|
-
-
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
190
|
+
- 'x',
|
|
191
|
+
- 'x2',
|
|
192
|
+
- "x'",
|
|
193
|
+
- 'y',
|
|
194
|
+
- 'y2',
|
|
195
|
+
- "y'",
|
|
196
|
+
- 'z',
|
|
197
|
+
- 'z2',
|
|
198
|
+
- "z'",
|
|
195
199
|
|
|
196
200
|
#### Example
|
|
197
201
|
|
|
@@ -225,25 +229,25 @@ cube.dispatchEvent(event);
|
|
|
225
229
|
|
|
226
230
|
actionIDs for action type "movement" are as follows
|
|
227
231
|
|
|
228
|
-
-
|
|
229
|
-
-
|
|
230
|
-
-
|
|
231
|
-
-
|
|
232
|
-
-
|
|
233
|
-
-
|
|
234
|
-
-
|
|
235
|
-
-
|
|
236
|
-
-
|
|
237
|
-
-
|
|
238
|
-
-
|
|
239
|
-
-
|
|
240
|
-
-
|
|
241
|
-
-
|
|
242
|
-
-
|
|
243
|
-
-
|
|
244
|
-
-
|
|
245
|
-
-
|
|
246
|
-
-
|
|
232
|
+
- 'R',
|
|
233
|
+
- 'R2',
|
|
234
|
+
- "R'",
|
|
235
|
+
- 'L',
|
|
236
|
+
- 'L2',
|
|
237
|
+
- "L'",
|
|
238
|
+
- 'U',
|
|
239
|
+
- 'U2',
|
|
240
|
+
- "U'",
|
|
241
|
+
- 'D',
|
|
242
|
+
- 'D2',
|
|
243
|
+
- "D'",
|
|
244
|
+
- 'F',
|
|
245
|
+
- 'F2',
|
|
246
|
+
- "F'",
|
|
247
|
+
- 'B',
|
|
248
|
+
- 'B2',
|
|
249
|
+
- "B'",
|
|
250
|
+
- etc...
|
|
247
251
|
|
|
248
252
|
#### Example
|
|
249
253
|
|
package/index.js
CHANGED
|
@@ -1,54 +1,114 @@
|
|
|
1
|
-
import { Scene, WebGLRenderer, PerspectiveCamera, AmbientLight, DirectionalLight } from 'three';
|
|
2
|
-
import { Tween, Group, Easing } from '@tweenjs/tween.js';
|
|
1
|
+
import { Scene, WebGLRenderer, PerspectiveCamera, AmbientLight, DirectionalLight, Spherical } from 'three';
|
|
3
2
|
import { OrbitControls } from 'three/examples/jsm/Addons.js';
|
|
4
3
|
import Cube from './src/cube/cube';
|
|
5
4
|
import getRotationDetailsFromNotation from './src/utils/rotation';
|
|
6
5
|
import { debounce } from './src/utils/debouncer';
|
|
6
|
+
import gsap from 'gsap';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
/** @typedef {{ animationStyle: "exponential" | "next" | "fixed" | "match", animationSpeedMs: number, pieceGap: number, cameraSpeedMs: number, cameraRadius: number, cameraPeekAngleHorizontal: number, cameraPeekAngleVertical: number, cameraFieldOfView: number }} Settings */
|
|
9
|
+
/** @type {Settings} */
|
|
10
|
+
const defaultSettings = {
|
|
11
|
+
animationSpeedMs: 100,
|
|
12
|
+
animationStyle: 'fixed',
|
|
13
|
+
pieceGap: 1.04,
|
|
14
|
+
cameraSpeedMs: 100,
|
|
15
|
+
cameraRadius: 5,
|
|
16
|
+
cameraPeekAngleHorizontal: 0.6,
|
|
17
|
+
cameraPeekAngleVertical: 0.6,
|
|
18
|
+
cameraFieldOfView: 75,
|
|
19
|
+
};
|
|
20
|
+
const minGap = 1;
|
|
21
|
+
const minRadius = 4;
|
|
22
|
+
const minFieldOfView = 30;
|
|
23
|
+
const maxFieldOfView = 100;
|
|
24
|
+
const maxAzimuthAngle = (5 * Math.PI) / 16;
|
|
25
|
+
const polarAngleOffset = Math.PI / 2;
|
|
26
|
+
const maxPolarAngle = (5 * Math.PI) / 16;
|
|
13
27
|
|
|
14
28
|
class RubiksCube extends HTMLElement {
|
|
15
29
|
constructor() {
|
|
16
30
|
super();
|
|
17
|
-
/** @type {number} */
|
|
18
|
-
this.animationSpeed = defaultAnimationSpeed;
|
|
19
31
|
this.attachShadow({ mode: 'open' });
|
|
20
32
|
this.shadowRoot.innerHTML = `<canvas id="cube-canvas" style="display:block;"></canvas>`;
|
|
21
33
|
this.canvas = this.shadowRoot.getElementById('cube-canvas');
|
|
22
|
-
/** @type {
|
|
34
|
+
/** @type {Settings} */
|
|
23
35
|
this.settings = {
|
|
24
|
-
|
|
25
|
-
animationStyle: this.getAttribute('animation-style') ||
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
animationSpeedMs: this.getAttribute('animation-speed-ms') || defaultSettings.animationSpeedMs,
|
|
37
|
+
animationStyle: this.getAttribute('animation-style') || defaultSettings.animationStyle,
|
|
38
|
+
pieceGap: this.getAttribute('piece-gap') || defaultSettings.pieceGap,
|
|
39
|
+
cameraSpeedMs: this.getAttribute('camera-speed-ms') || defaultSettings.cameraSpeedMs,
|
|
40
|
+
cameraRadius: this.getAttribute('camera-radius') || defaultSettings.cameraRadius,
|
|
41
|
+
cameraPeekAngleHorizontal: this.getAttribute('camera-peek-angle-horizontal') || defaultSettings.cameraPeekAngleHorizontal,
|
|
42
|
+
cameraPeekAngleVertical: this.getAttribute('camera-peek-angle-vertical') || defaultSettings.cameraPeekAngleVertical,
|
|
43
|
+
cameraFieldOfView: this.getAttribute('camera-field-of-view') || defaultSettings.cameraFieldOfView,
|
|
28
44
|
};
|
|
29
45
|
}
|
|
30
46
|
|
|
31
47
|
static get observedAttributes() {
|
|
32
|
-
return [
|
|
48
|
+
return [
|
|
49
|
+
'animation-style',
|
|
50
|
+
'animation-speed-ms',
|
|
51
|
+
'piece-gap',
|
|
52
|
+
'camera-speed-ms',
|
|
53
|
+
'camera-radius',
|
|
54
|
+
'camera-peek-angle-horizontal',
|
|
55
|
+
'camera-peek-angle-vertical',
|
|
56
|
+
'camera-field-of-view',
|
|
57
|
+
];
|
|
33
58
|
}
|
|
34
59
|
|
|
35
60
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
36
61
|
if (name === 'animation-style') {
|
|
37
62
|
this.settings.animationStyle = newVal;
|
|
38
63
|
}
|
|
39
|
-
if (name === 'animation-speed') {
|
|
64
|
+
if (name === 'animation-speed-ms') {
|
|
40
65
|
var speed = Number(newVal);
|
|
41
|
-
this.settings.
|
|
66
|
+
this.settings.animationSpeedMs = speed > 0 ? speed : 0;
|
|
42
67
|
}
|
|
43
68
|
if (name === 'piece-gap') {
|
|
44
69
|
var gap = Number(newVal);
|
|
45
|
-
this.settings.
|
|
70
|
+
this.settings.pieceGap = gap < minGap ? minGap : gap;
|
|
46
71
|
}
|
|
47
|
-
if (name === 'camera-speed') {
|
|
72
|
+
if (name === 'camera-speed-ms') {
|
|
48
73
|
var speed = Number(newVal);
|
|
49
|
-
this.settings.
|
|
74
|
+
this.settings.cameraSpeedMs = speed > 0 ? speed : 0;
|
|
75
|
+
}
|
|
76
|
+
if (name === 'camera-radius') {
|
|
77
|
+
var radius = Number(newVal);
|
|
78
|
+
this.settings.cameraRadius = radius < minRadius ? minRadius : radius;
|
|
79
|
+
if (oldVal !== newVal && oldVal !== null) {
|
|
80
|
+
this.dispatchEvent(new CustomEvent('cameraSettingsChanged'));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (name === 'camera-peek-angle-horizontal') {
|
|
84
|
+
var angle = Number(newVal);
|
|
85
|
+
angle = angle > 0 ? angle : 0;
|
|
86
|
+
angle = angle < 1 ? angle : 1;
|
|
87
|
+
this.settings.cameraPeekAngleHorizontal = angle > 0 ? angle : 0;
|
|
88
|
+
if (oldVal !== newVal && oldVal !== null) {
|
|
89
|
+
this.dispatchEvent(new CustomEvent('cameraSettingsChanged'));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (name === 'camera-peek-angle-vertical') {
|
|
93
|
+
var angle = Number(newVal);
|
|
94
|
+
angle = angle > 0 ? angle : 0;
|
|
95
|
+
angle = angle < 1 ? angle : 1;
|
|
96
|
+
this.settings.cameraPeekAngleVertical = angle;
|
|
97
|
+
if (oldVal !== newVal && oldVal !== null) {
|
|
98
|
+
this.dispatchEvent(new CustomEvent('cameraSettingsChanged'));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (name == 'camera-field-of-view') {
|
|
102
|
+
var fov = Number(newVal);
|
|
103
|
+
fov = fov > minFieldOfView ? fov : minFieldOfView;
|
|
104
|
+
fov = fov < maxFieldOfView ? fov : maxFieldOfView;
|
|
105
|
+
this.settings.cameraFieldOfView = fov;
|
|
106
|
+
if (oldVal !== newVal && oldVal !== null) {
|
|
107
|
+
this.dispatchEvent(new CustomEvent('cameraFieldOfViewChanged'));
|
|
108
|
+
}
|
|
50
109
|
}
|
|
51
110
|
}
|
|
111
|
+
|
|
52
112
|
connectedCallback() {
|
|
53
113
|
this.init();
|
|
54
114
|
}
|
|
@@ -77,22 +137,21 @@ class RubiksCube extends HTMLElement {
|
|
|
77
137
|
).observe(this);
|
|
78
138
|
|
|
79
139
|
// add camera
|
|
80
|
-
const camera = new PerspectiveCamera(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
camera.position.x = 0;
|
|
140
|
+
const camera = new PerspectiveCamera(this.settings.cameraFieldOfView, this.clientWidth / this.clientHeight, 1, 2000);
|
|
141
|
+
const cameraSpherical = new Spherical(50, (3 * Math.PI) / 8, -Math.PI / 4);
|
|
142
|
+
camera.position.setFromSpherical(cameraSpherical);
|
|
143
|
+
/** @type {{ Up: boolean, Right: boolean }} */
|
|
144
|
+
const cameraState = { Up: true, Right: true };
|
|
86
145
|
|
|
87
146
|
// add orbit controls for camera
|
|
88
147
|
const controls = new OrbitControls(camera, renderer.domElement);
|
|
89
148
|
controls.enableZoom = false;
|
|
90
149
|
controls.enablePan = false;
|
|
91
150
|
controls.enableDamping = true;
|
|
92
|
-
controls.maxAzimuthAngle =
|
|
93
|
-
controls.minAzimuthAngle = -
|
|
94
|
-
controls.maxPolarAngle =
|
|
95
|
-
controls.minPolarAngle =
|
|
151
|
+
controls.maxAzimuthAngle = maxAzimuthAngle;
|
|
152
|
+
controls.minAzimuthAngle = -maxAzimuthAngle;
|
|
153
|
+
controls.maxPolarAngle = polarAngleOffset + maxPolarAngle;
|
|
154
|
+
controls.minPolarAngle = polarAngleOffset - maxPolarAngle;
|
|
96
155
|
|
|
97
156
|
// add lighting to scene
|
|
98
157
|
const ambientLight = new AmbientLight('white', 0.5);
|
|
@@ -110,10 +169,6 @@ class RubiksCube extends HTMLElement {
|
|
|
110
169
|
const cube = new Cube(this.settings);
|
|
111
170
|
scene.add(cube.group, cube.rotationGroup);
|
|
112
171
|
|
|
113
|
-
// initial camera animation
|
|
114
|
-
const cameraAnimationGroup = new Group();
|
|
115
|
-
cameraAnimationGroup.add(new Tween(camera.position).to({ x: 2.5, y: 2.5, z: 4 }, 1000).easing(Easing.Cubic.InOut).start());
|
|
116
|
-
|
|
117
172
|
const sendState = (eventId) => {
|
|
118
173
|
const event = new CustomEvent('state', { detail: { eventId, state: cube.currentState } });
|
|
119
174
|
this.dispatchEvent(event);
|
|
@@ -121,7 +176,6 @@ class RubiksCube extends HTMLElement {
|
|
|
121
176
|
|
|
122
177
|
// animation loop
|
|
123
178
|
function animate() {
|
|
124
|
-
cameraAnimationGroup.update();
|
|
125
179
|
controls.update();
|
|
126
180
|
|
|
127
181
|
var eventId = cube.update();
|
|
@@ -141,7 +195,8 @@ class RubiksCube extends HTMLElement {
|
|
|
141
195
|
/** @type {{eventId: string, action: {type: "movement" | "camera" | "rotation", actionId: string }}} move */
|
|
142
196
|
var move = e.detail.move;
|
|
143
197
|
if (move.action.type === 'camera') {
|
|
144
|
-
|
|
198
|
+
updateCameraState(move.action.actionId);
|
|
199
|
+
updateCameraPosition();
|
|
145
200
|
return;
|
|
146
201
|
}
|
|
147
202
|
if (move.action.type === 'movement' || move.action.type === 'rotation') {
|
|
@@ -162,9 +217,9 @@ class RubiksCube extends HTMLElement {
|
|
|
162
217
|
};
|
|
163
218
|
|
|
164
219
|
/**
|
|
165
|
-
* @param {'peek-toggle-horizontal' | 'peek-toggle-vertical' | 'peek-right' | 'peek-left' | 'peek-up' | 'peek-down'} actionId
|
|
220
|
+
* @param {'peek-toggle-horizontal' | 'peek-toggle-vertical' | 'peek-right' | 'peek-left' | 'peek-up' | 'peek-down' } actionId
|
|
166
221
|
*/
|
|
167
|
-
const
|
|
222
|
+
const updateCameraState = (actionId) => {
|
|
168
223
|
if (actionId === 'peek-toggle-horizontal') {
|
|
169
224
|
cameraState.Right = !cameraState.Right;
|
|
170
225
|
} else if (actionId === 'peek-toggle-vertical') {
|
|
@@ -178,19 +233,42 @@ class RubiksCube extends HTMLElement {
|
|
|
178
233
|
} else if (actionId === 'peek-down') {
|
|
179
234
|
cameraState.Up = false;
|
|
180
235
|
}
|
|
181
|
-
cameraAnimationGroup.add(
|
|
182
|
-
new Tween(camera.position)
|
|
183
|
-
.to(
|
|
184
|
-
{
|
|
185
|
-
x: cameraState.Right ? cameraState.RightDistance : -cameraState.RightDistance,
|
|
186
|
-
y: cameraState.Up ? cameraState.UpDistance : -cameraState.UpDistance,
|
|
187
|
-
z: 4,
|
|
188
|
-
},
|
|
189
|
-
this.settings.cameraSpeed,
|
|
190
|
-
)
|
|
191
|
-
.start(),
|
|
192
|
-
);
|
|
193
236
|
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @param {number | null} cameraSpeedMs
|
|
240
|
+
* @param {gsap.EaseString | gsap.EaseFunction | undefined} ease
|
|
241
|
+
*/
|
|
242
|
+
const updateCameraPosition = (cameraSpeedMs = this.settings.cameraSpeedMs, ease = 'none') => {
|
|
243
|
+
cameraSpeedMs = cameraSpeedMs ? cameraSpeedMs : this.settings.cameraSpeedMs;
|
|
244
|
+
var phi = polarAngleOffset + (cameraState.Up ? -this.settings.cameraPeekAngleVertical : this.settings.cameraPeekAngleVertical) * maxPolarAngle;
|
|
245
|
+
var theta = (cameraState.Right ? this.settings.cameraPeekAngleHorizontal : -this.settings.cameraPeekAngleHorizontal) * maxAzimuthAngle;
|
|
246
|
+
const startSpherical = new Spherical().setFromVector3(camera.position);
|
|
247
|
+
const targetSpherical = new Spherical(this.settings.cameraRadius, phi, theta);
|
|
248
|
+
gsap.to(startSpherical, {
|
|
249
|
+
radius: targetSpherical.radius,
|
|
250
|
+
theta: targetSpherical.theta,
|
|
251
|
+
phi: targetSpherical.phi,
|
|
252
|
+
duration: cameraSpeedMs / 1000,
|
|
253
|
+
ease: ease,
|
|
254
|
+
onUpdate: function () {
|
|
255
|
+
camera.position.setFromSpherical(startSpherical);
|
|
256
|
+
camera.lookAt(cube.group.position);
|
|
257
|
+
controls.update();
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
this.addEventListener('cameraSettingsChanged', () => {
|
|
263
|
+
updateCameraPosition(); // animate settings changes
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
this.addEventListener('cameraFieldOfViewChanged', () => {
|
|
267
|
+
camera.fov = this.settings.cameraFieldOfView;
|
|
268
|
+
camera.updateProjectionMatrix();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
updateCameraPosition(1000, 'none'); // initial animation
|
|
194
272
|
}
|
|
195
273
|
}
|
|
196
274
|
customElements.define('rubiks-cube', RubiksCube);
|
package/package.json
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@houstonp/rubiks-cube",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Rubiks Cube Web Component built with threejs",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"author": "Houston Pearse",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"
|
|
9
|
+
"gsap": "^3.14.2",
|
|
10
10
|
"three": "^0.167.1"
|
|
11
11
|
},
|
|
12
|
-
"devDependencies": {},
|
|
13
12
|
"repository": {
|
|
14
13
|
"type": "git",
|
|
15
14
|
"url": "git+https://github.com/houstonpearse/rubiks-cube.git"
|
package/src/cube/cube.js
CHANGED
|
@@ -5,10 +5,10 @@ import { CubeRotation } from './cubeRotation';
|
|
|
5
5
|
|
|
6
6
|
export default class Cube {
|
|
7
7
|
/**
|
|
8
|
-
* @param {
|
|
8
|
+
* @param {import('../..').Settings} settings
|
|
9
9
|
*/
|
|
10
10
|
constructor(settings) {
|
|
11
|
-
/** @type {
|
|
11
|
+
/** @type {import('../..').Settings} */
|
|
12
12
|
this.settings = settings;
|
|
13
13
|
/** @type {Group} */
|
|
14
14
|
this.group = this.createCubeGroup();
|
|
@@ -45,7 +45,11 @@ export default class Cube {
|
|
|
45
45
|
|
|
46
46
|
for (const piece of createCubeState()) {
|
|
47
47
|
var pieceGroup = piece.group;
|
|
48
|
-
pieceGroup.position.set(
|
|
48
|
+
pieceGroup.position.set(
|
|
49
|
+
piece.position.x * this.settings.pieceGap,
|
|
50
|
+
piece.position.y * this.settings.pieceGap,
|
|
51
|
+
piece.position.z * this.settings.pieceGap,
|
|
52
|
+
);
|
|
49
53
|
pieceGroup.rotation.set(piece.rotation.x, piece.rotation.y, piece.rotation.z);
|
|
50
54
|
pieceGroup.userData = {
|
|
51
55
|
position: Object.assign({}, piece.position),
|
|
@@ -61,11 +65,11 @@ export default class Cube {
|
|
|
61
65
|
|
|
62
66
|
/**
|
|
63
67
|
* update the cube and continue any rotations
|
|
64
|
-
* @returns {
|
|
68
|
+
* @returns {string}
|
|
65
69
|
*/
|
|
66
70
|
update() {
|
|
67
71
|
if (this.currentRotation === undefined) {
|
|
68
|
-
if (this._lastGap !== this.settings.
|
|
72
|
+
if (this._lastGap !== this.settings.pieceGap) {
|
|
69
73
|
this.updateGap();
|
|
70
74
|
}
|
|
71
75
|
this.currentRotation = this.rotationQueue.shift();
|
|
@@ -100,9 +104,9 @@ export default class Cube {
|
|
|
100
104
|
if (this.currentRotation === undefined) {
|
|
101
105
|
this.group.children.forEach((piece) => {
|
|
102
106
|
var { x, y, z } = piece.userData.position;
|
|
103
|
-
piece.position.set(x * this.settings.
|
|
107
|
+
piece.position.set(x * this.settings.pieceGap, y * this.settings.pieceGap, z * this.settings.pieceGap);
|
|
104
108
|
});
|
|
105
|
-
this._lastGap = this.settings.
|
|
109
|
+
this._lastGap = this.settings.pieceGap;
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
112
|
|
|
@@ -118,15 +122,15 @@ export default class Cube {
|
|
|
118
122
|
*/
|
|
119
123
|
getRotationSpeed() {
|
|
120
124
|
if (this.settings.animationStyle === 'exponential') {
|
|
121
|
-
return this.settings.
|
|
125
|
+
return this.settings.animationSpeedMs / 2 ** this.rotationQueue.length;
|
|
122
126
|
}
|
|
123
127
|
if (this.settings.animationStyle === 'next') {
|
|
124
|
-
return this.rotationQueue.length > 0 ? 0 : this.settings.
|
|
128
|
+
return this.rotationQueue.length > 0 ? 0 : this.settings.animationSpeedMs;
|
|
125
129
|
}
|
|
126
130
|
if (this.settings.animationStyle === 'match') {
|
|
127
131
|
if (this.rotationQueue.length > 0) {
|
|
128
132
|
var lastTimeStamp = this.currentRotation.timestampMs;
|
|
129
|
-
var minGap = this._matchSpeed ?? this.settings.
|
|
133
|
+
var minGap = this._matchSpeed ?? this.settings.animationSpeedMs;
|
|
130
134
|
for (var i = 0; i < this.rotationQueue.length; i++) {
|
|
131
135
|
var gap = this.rotationQueue[i].timestampMs - lastTimeStamp;
|
|
132
136
|
if (gap < minGap) {
|
|
@@ -138,12 +142,12 @@ export default class Cube {
|
|
|
138
142
|
if (this._matchSpeed !== undefined) {
|
|
139
143
|
return this._matchSpeed;
|
|
140
144
|
}
|
|
141
|
-
return this.settings.
|
|
145
|
+
return this.settings.animationSpeedMs;
|
|
142
146
|
}
|
|
143
147
|
if (this.settings.animationStyle === 'fixed') {
|
|
144
|
-
return this.settings.
|
|
148
|
+
return this.settings.animationSpeedMs;
|
|
145
149
|
}
|
|
146
|
-
return this.settings.
|
|
150
|
+
return this.settings.animationSpeedMs;
|
|
147
151
|
}
|
|
148
152
|
|
|
149
153
|
/**
|
|
@@ -160,7 +164,7 @@ export default class Cube {
|
|
|
160
164
|
this.group.children.forEach((piece) => {
|
|
161
165
|
const { x, y, z } = piece.userData.initialPosition;
|
|
162
166
|
const { x: u, y: v, z: w } = piece.userData.initialRotation;
|
|
163
|
-
piece.position.set(x * this.settings.
|
|
167
|
+
piece.position.set(x * this.settings.pieceGap, y * this.settings.pieceGap, z * this.settings.pieceGap);
|
|
164
168
|
piece.rotation.set(u, v, w);
|
|
165
169
|
piece.userData.position.x = x;
|
|
166
170
|
piece.userData.position.y = y;
|