arcanumcube 0.1.0 → 0.1.2

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 CHANGED
@@ -1,6 +1,19 @@
1
1
  # Arcanum Cube
2
2
 
3
- Arcanum Cube is a cube puzzle module written in Typescript. Supports creation and manipulation of WebGL mesh groups.
3
+ Arcanum Cube Arcanum Cube is a WebGL cube puzzle module written in TypeScript. You can create Three.js meshes group and twist cube.
4
+
5
+ ## Demo Page
6
+
7
+ - [Example](https://mawxiwtz.github.io/arcanumcube/) \
8
+ Rotation only
9
+
10
+ ## Installation
11
+
12
+ You can add arcanumcube as an npm dependency:
13
+
14
+ ```
15
+ npm install arcanumcube
16
+ ```
4
17
 
5
18
  ## Usage
6
19
 
@@ -14,11 +27,14 @@ import * as ARCCUBE from 'arcanumcube';
14
27
  2. create a cube object
15
28
 
16
29
  ```
30
+ const scene = new THREE.Scene();
31
+ :
17
32
  const arccube = new ARCCUBE.WebGLArcanumCube();
18
33
  await arccube.init();
19
34
  const arccubeGroup = arccube.getGroup();
20
35
  arccubeGroup.position.set(0, 0, 0);
21
36
  scene.add(arccubeGroup);
37
+ :
22
38
 
23
39
  renderer.setAnimationLoop((time) => {
24
40
  :
@@ -41,6 +57,10 @@ arccube.tweenTwist('U');
41
57
  arccube.reset();
42
58
  ```
43
59
 
60
+ ## Document
61
+
62
+ Currently under construction
63
+
44
64
  ## License
45
65
 
46
66
  Released under the MIT license
@@ -41,6 +41,9 @@ __export(arcanumcube_exports, {
41
41
  DefaultModel: () => DefaultModel,
42
42
  DefaultSkin: () => DefaultSkin,
43
43
  FACE: () => FACE,
44
+ GetSkinByName: () => GetSkinByName,
45
+ GetSkinNameList: () => GetSkinNameList,
46
+ MatchGoalState: () => MatchGoalState,
44
47
  SIDE_MAX: () => SIDE_MAX,
45
48
  SIDE_MIDDLE: () => SIDE_MIDDLE,
46
49
  SIDE_MIN: () => SIDE_MIN,
@@ -327,6 +330,42 @@ function getRandomTwistList(steps = 0) {
327
330
  }
328
331
  return list;
329
332
  }
333
+ var SIDE_FACES = Object.freeze([
334
+ [1, 2, 4, 5],
335
+ [2, 0, 5, 3],
336
+ [0, 1, 3, 4],
337
+ [2, 1, 5, 4],
338
+ [0, 2, 3, 5],
339
+ [1, 0, 4, 3]
340
+ ]);
341
+ function getInitialState(up, front) {
342
+ const down = (up + 3) % 6;
343
+ const side = SIDE_FACES[up];
344
+ const state = new Array(CUBE_SIZE * CUBE_SIZE).fill(up);
345
+ for (let i = 0; i < 4; i++) {
346
+ if (i == 2) {
347
+ const downs = [...Array(CUBE_SIZE * CUBE_SIZE)].fill(down);
348
+ state.push(...downs);
349
+ }
350
+ const sides = [...Array(CUBE_SIZE * CUBE_SIZE)].fill(side[(front + i) % 4]);
351
+ state.push(...sides);
352
+ }
353
+ return state;
354
+ }
355
+ function isSameArrays(arr1, arr2) {
356
+ if (arr1.length !== arr2.length) return false;
357
+ return !arr1.some((v, i) => v !== arr2[i]);
358
+ }
359
+ var GOAL_STATE_LIST = [];
360
+ for (let up = 0; up < 6; up++) {
361
+ for (let front = 0; front < 4; front++) {
362
+ GOAL_STATE_LIST.push(getInitialState(up, front));
363
+ }
364
+ }
365
+ Object.freeze(GOAL_STATE_LIST);
366
+ function MatchGoalState(state) {
367
+ return GOAL_STATE_LIST.some((s) => isSameArrays(state, s));
368
+ }
330
369
  var Cube = class {
331
370
  type;
332
371
  position;
@@ -471,6 +510,9 @@ var ArcanumCube = class {
471
510
  const list = this.getUndoList(steps);
472
511
  this.twist(list, true);
473
512
  }
513
+ isSolved() {
514
+ return MatchGoalState(this.getStickerColors());
515
+ }
474
516
  getHistory() {
475
517
  return this._history;
476
518
  }
@@ -693,6 +735,12 @@ function createDefaultLogoTexture() {
693
735
  texture.needsUpdate = true;
694
736
  return texture;
695
737
  }
738
+ function GetSkinByName(name) {
739
+ return SkinMap[name];
740
+ }
741
+ function GetSkinNameList() {
742
+ return Object.keys(SkinMap);
743
+ }
696
744
  var standardSkin = {
697
745
  name: "Standard",
698
746
  enableEnvMap: false,
@@ -1191,12 +1239,14 @@ var WebGLCube = class extends Cube {
1191
1239
  stickerScale: 0.92,
1192
1240
  gap: 0.01,
1193
1241
  enableShadow: false,
1194
- skin: DefaultSkin.name
1242
+ skin: DefaultSkin,
1243
+ wireframe: false,
1244
+ wireframeColor: 32768
1195
1245
  };
1196
1246
  if (opts) {
1197
1247
  Object.assign(this._config, opts);
1198
1248
  }
1199
- this._skin = SkinMap[this._config.skin];
1249
+ this._skin = this._config.skin;
1200
1250
  }
1201
1251
  getGroup() {
1202
1252
  return this._group;
@@ -1230,9 +1280,13 @@ var WebGLCube = class extends Cube {
1230
1280
  const geo = mesh.geometry.clone();
1231
1281
  geo.scale(scale, scale, scale);
1232
1282
  const mat = this._skin.cube.material();
1233
- if (this._skin.enableEnvMap && config.envMap && (mat instanceof THREE3.MeshStandardMaterial || mat instanceof THREE3.MeshBasicMaterial)) {
1283
+ if (this._skin.enableEnvMap && config.envMap && (mat instanceof THREE3.MeshStandardMaterial || mat instanceof THREE3.MeshBasicMaterial || mat instanceof THREE3.MeshPhysicalMaterial)) {
1234
1284
  mat.envMap = config.envMap;
1235
1285
  }
1286
+ if (config.wireframe) {
1287
+ mat.wireframe = config.wireframe;
1288
+ mat.color = new THREE3.Color(config.wireframeColor);
1289
+ }
1236
1290
  const m = new THREE3.Mesh(geo, mat);
1237
1291
  m.name = this.type;
1238
1292
  for (const r of angles) {
@@ -1242,6 +1296,7 @@ var WebGLCube = class extends Cube {
1242
1296
  m.geometry.rotateZ(Math.PI * axis[2] * steps / 2);
1243
1297
  }
1244
1298
  m.castShadow = config.enableShadow;
1299
+ m.receiveShadow = config.enableShadow;
1245
1300
  m.position.x += (x - 1) * CUBE_SIDE_LEN * (1 + config.gap) * scale;
1246
1301
  m.position.y += (y - 1) * CUBE_SIDE_LEN * (1 + config.gap) * scale;
1247
1302
  m.position.z += (z - 1) * CUBE_SIDE_LEN * (1 + config.gap) * scale;
@@ -1266,12 +1321,17 @@ var WebGLCube = class extends Cube {
1266
1321
  pgeo.scale(scale * config.stickerScale, scale, scale * config.stickerScale);
1267
1322
  sticker.color = sticker.face;
1268
1323
  const pmat = this._skin.sticker.material(x, y, z, sticker.color);
1269
- if (this._skin.enableEnvMap && config.envMap && (pmat instanceof THREE3.MeshStandardMaterial || pmat instanceof THREE3.MeshBasicMaterial)) {
1324
+ if (this._skin.enableEnvMap && config.envMap && (pmat instanceof THREE3.MeshStandardMaterial || pmat instanceof THREE3.MeshBasicMaterial || pmat instanceof THREE3.MeshPhysicalMaterial)) {
1270
1325
  pmat.envMap = config.envMap;
1271
1326
  }
1327
+ if (config.wireframe) {
1328
+ pmat.wireframe = config.wireframe;
1329
+ pmat.color = new THREE3.Color(config.wireframeColor);
1330
+ }
1272
1331
  const pm = new THREE3.Mesh(pgeo, pmat);
1273
1332
  pm.name = CUBE.STICKER;
1274
1333
  pm.castShadow = config.enableShadow;
1334
+ m.receiveShadow = config.enableShadow;
1275
1335
  const stickerAngle = STICKER_FACE_2_ANGLE[sticker.face];
1276
1336
  pm.geometry.rotateX(Math.PI * stickerAngle[0] / 180);
1277
1337
  pm.geometry.rotateY(Math.PI * stickerAngle[1] / 180);
@@ -1356,7 +1416,7 @@ var WebGLArcanumCube = class extends ArcanumCube {
1356
1416
  /** tween group */
1357
1417
  _tweens;
1358
1418
  /** light at the center of cube */
1359
- _pointLights;
1419
+ _coreLights;
1360
1420
  constructor(options) {
1361
1421
  super(options);
1362
1422
  this._config = {
@@ -1367,8 +1427,14 @@ var WebGLArcanumCube = class extends ArcanumCube {
1367
1427
  stickerScale: 0.92,
1368
1428
  gap: 0.01,
1369
1429
  enableShadow: false,
1370
- skin: DefaultSkin.name,
1371
- enableLight: false
1430
+ skin: DefaultSkin,
1431
+ autoReset: true,
1432
+ enableCoreLight: false,
1433
+ coreLightColor: 33023,
1434
+ coreLightIntensity: 30,
1435
+ wireframe: false,
1436
+ wireframeColor: 32768,
1437
+ twistOptions: {}
1372
1438
  };
1373
1439
  this._matrix = [];
1374
1440
  this._group = new THREE3.Group();
@@ -1376,7 +1442,7 @@ var WebGLArcanumCube = class extends ArcanumCube {
1376
1442
  this._cubeMap = {};
1377
1443
  this._cancelDragDeg = 15;
1378
1444
  this._tweens = new TWEEN.Group();
1379
- this._pointLights = [];
1445
+ this._coreLights = [];
1380
1446
  if (options) {
1381
1447
  Object.assign(this._config, options);
1382
1448
  }
@@ -1387,11 +1453,8 @@ var WebGLArcanumCube = class extends ArcanumCube {
1387
1453
  getCubeObjectList() {
1388
1454
  return this._cubeObjectList;
1389
1455
  }
1390
- static getSkinNameList() {
1391
- return Object.keys(SkinMap);
1392
- }
1393
1456
  async init() {
1394
- const skin = SkinMap[this._config.skin];
1457
+ const skin = this._config.skin;
1395
1458
  if (skin.modelLoading) {
1396
1459
  this._init();
1397
1460
  } else {
@@ -1405,7 +1468,7 @@ var WebGLArcanumCube = class extends ArcanumCube {
1405
1468
  this._cubeMap = {};
1406
1469
  this._matrix = [];
1407
1470
  this._history = [];
1408
- this._pointLights = [];
1471
+ this._coreLights = [];
1409
1472
  const fixedGroups = new THREE3.Group();
1410
1473
  const config = this._config;
1411
1474
  const yarray = [];
@@ -1420,7 +1483,9 @@ var WebGLArcanumCube = class extends ArcanumCube {
1420
1483
  gap: config.gap,
1421
1484
  enableShadow: config.enableShadow,
1422
1485
  skin: config.skin,
1423
- envMap: config.envMap
1486
+ envMap: config.envMap,
1487
+ wireframe: config.wireframe,
1488
+ wireframeColor: config.wireframeColor
1424
1489
  });
1425
1490
  cube.init();
1426
1491
  xarray.push(cube);
@@ -1428,13 +1493,18 @@ var WebGLArcanumCube = class extends ArcanumCube {
1428
1493
  this._cubeObjectList.push(entityGroup);
1429
1494
  this._cubeMap[entityGroup.id] = cube;
1430
1495
  fixedGroups.add(cube.getGroup());
1431
- if (config.enableLight) {
1496
+ if (config.enableCoreLight) {
1432
1497
  if (x !== SIDE_MIN && y !== SIDE_MIN && z !== SIDE_MIN) {
1433
- const light = new THREE3.PointLight(33023, 30, 20, 0.1);
1498
+ const light = new THREE3.PointLight(
1499
+ config.wireframe ? config.wireframeColor : config.coreLightColor,
1500
+ config.coreLightIntensity,
1501
+ 20,
1502
+ 0.1
1503
+ );
1434
1504
  light.position.x = (x - 1 / 2) * CUBE_SIDE_LEN * (1 + config.gap) * config.scale;
1435
1505
  light.position.y = (y - 1 / 2) * CUBE_SIDE_LEN * (1 + config.gap) * config.scale;
1436
1506
  light.position.z += (z - 1 / 2) * CUBE_SIDE_LEN * (1 + config.gap) * config.scale;
1437
- this._pointLights.push(light);
1507
+ this._coreLights.push(light);
1438
1508
  }
1439
1509
  }
1440
1510
  }
@@ -1444,14 +1514,14 @@ var WebGLArcanumCube = class extends ArcanumCube {
1444
1514
  }
1445
1515
  this._matrix = yarray;
1446
1516
  this._group.clear();
1447
- if (config.enableLight) {
1448
- this._pointLights.forEach((light) => {
1517
+ if (config.enableCoreLight) {
1518
+ this._coreLights.forEach((light) => {
1449
1519
  this._group.add(light);
1450
1520
  });
1451
1521
  }
1452
1522
  this._group.add(fixedGroups);
1453
1523
  }
1454
- async setSkin(name) {
1524
+ async setSkin(skin) {
1455
1525
  const dispose = (obj) => {
1456
1526
  if (obj instanceof THREE3.Group) {
1457
1527
  for (const o of obj.children) {
@@ -1463,7 +1533,7 @@ var WebGLArcanumCube = class extends ArcanumCube {
1463
1533
  obj.geometry.dispose();
1464
1534
  }
1465
1535
  };
1466
- this._config.skin = name;
1536
+ this._config.skin = skin;
1467
1537
  for (const obj of this._group.children) {
1468
1538
  dispose(obj);
1469
1539
  }
@@ -1647,8 +1717,8 @@ var WebGLArcanumCube = class extends ArcanumCube {
1647
1717
  }
1648
1718
  }
1649
1719
  this._group.clear();
1650
- if (this._config.enableLight) {
1651
- this._pointLights.forEach((light) => {
1720
+ if (this._config.enableCoreLight) {
1721
+ this._coreLights.forEach((light) => {
1652
1722
  this._group.add(light);
1653
1723
  });
1654
1724
  }
@@ -1685,7 +1755,7 @@ var WebGLArcanumCube = class extends ArcanumCube {
1685
1755
  // twist randomly several steps
1686
1756
  scramble(steps = 0, duration = 3e3) {
1687
1757
  const list = getRandomTwistList(steps);
1688
- this.tweenTwist(list, false, duration);
1758
+ this.tweenTwist(list, false, duration, false);
1689
1759
  }
1690
1760
  undo(steps = 1, duration = 300) {
1691
1761
  const list = this.getUndoList(steps);
@@ -1693,17 +1763,25 @@ var WebGLArcanumCube = class extends ArcanumCube {
1693
1763
  }
1694
1764
  // twisting(複数回対応)
1695
1765
  // durationを0にするとTweenなしとなる
1696
- tweenTwist(twist, reverse = false, duration = 500, cancel = false) {
1766
+ tweenTwist(twist, reverse = false, duration = 500, cancel = false, options) {
1697
1767
  if (this._tweens.getAll().length > 0) return;
1768
+ if (options == null) options = this._config.twistOptions;
1698
1769
  if (duration === 0) {
1699
1770
  if (Array.isArray(twist)) {
1700
1771
  if (twist.length == 0) return;
1701
- for (const c of twist) {
1772
+ options?.onStart && options.onStart(this);
1773
+ const len = twist.length;
1774
+ for (let i = 0; i < len; i++) {
1775
+ const c = twist[i];
1702
1776
  this._immediatelyTwist(c, reverse);
1777
+ options?.onTwisted && options.onTwisted(this, c, i + 1, len);
1703
1778
  }
1704
1779
  } else {
1780
+ options?.onStart && options.onStart(this);
1705
1781
  this._immediatelyTwist(twist, reverse);
1782
+ options?.onTwisted && options.onTwisted(this, twist, 1, 1);
1706
1783
  }
1784
+ options?.onComplete && options.onComplete(this);
1707
1785
  return;
1708
1786
  }
1709
1787
  let firstTween = void 0;
@@ -1711,8 +1789,15 @@ var WebGLArcanumCube = class extends ArcanumCube {
1711
1789
  if (Array.isArray(twist)) {
1712
1790
  if (twist.length == 0) return;
1713
1791
  const lap = duration / twist.length;
1714
- for (const c of twist) {
1715
- const t = this._tweenTwist(c, reverse, lap, cancel);
1792
+ const len = twist.length;
1793
+ for (let i = 0; i < len; i++) {
1794
+ const c = twist[i];
1795
+ const opts = {};
1796
+ const ontwisted = options?.onTwisted;
1797
+ if (ontwisted)
1798
+ opts.onTwisted = (self, twist2, n1, n2) => ontwisted(this, twist2, i + 1, len);
1799
+ if (i === len - 1 && options?.onComplete) opts.onComplete = options.onComplete;
1800
+ const t = this._tweenTwist(c, reverse, lap, cancel, opts);
1716
1801
  this._tweens.add(t);
1717
1802
  if (!tween) {
1718
1803
  firstTween = tween = t;
@@ -1722,10 +1807,11 @@ var WebGLArcanumCube = class extends ArcanumCube {
1722
1807
  }
1723
1808
  }
1724
1809
  } else {
1725
- firstTween = this._tweenTwist(twist, reverse, duration, cancel);
1810
+ firstTween = this._tweenTwist(twist, reverse, duration, cancel, options);
1726
1811
  this._tweens.add(firstTween);
1727
1812
  }
1728
1813
  if (firstTween) {
1814
+ options?.onStart && options.onStart(this);
1729
1815
  firstTween.start();
1730
1816
  }
1731
1817
  }
@@ -1747,7 +1833,7 @@ var WebGLArcanumCube = class extends ArcanumCube {
1747
1833
  super.twist(twist, reverse);
1748
1834
  }
1749
1835
  // twist with tween
1750
- _tweenTwist(twist, reverse, duration, cancel) {
1836
+ _tweenTwist(twist, reverse, duration, cancel, options = {}) {
1751
1837
  let qa;
1752
1838
  if (this._draggingTwist) {
1753
1839
  this._twistGroup = this._draggingTwist.group;
@@ -1784,12 +1870,28 @@ var WebGLArcanumCube = class extends ArcanumCube {
1784
1870
  super.twist(twist, reverse);
1785
1871
  }
1786
1872
  this._tweens.remove(tween);
1873
+ options.onTwisted && options.onTwisted(this, twist, 1, 1);
1874
+ options.onComplete && options.onComplete(this);
1875
+ if (this._config.autoReset && this.isSolved()) this.reset(0);
1787
1876
  });
1788
1877
  return tween;
1789
1878
  }
1790
1879
  updateTweens() {
1791
1880
  this._tweens.update();
1792
1881
  }
1882
+ // set color of core lights
1883
+ setCoreLightColor(color) {
1884
+ const c = new THREE3.Color(color);
1885
+ this._coreLights.forEach((l) => {
1886
+ l.color = c;
1887
+ });
1888
+ }
1889
+ // change intensity of core lights
1890
+ setCoreLightIntensity(intensity) {
1891
+ this._coreLights.forEach((l) => {
1892
+ l.intensity = intensity;
1893
+ });
1894
+ }
1793
1895
  };
1794
1896
  // Annotate the CommonJS export names for ESM import in node:
1795
1897
  0 && (module.exports = {
@@ -1804,6 +1906,9 @@ var WebGLArcanumCube = class extends ArcanumCube {
1804
1906
  DefaultModel,
1805
1907
  DefaultSkin,
1806
1908
  FACE,
1909
+ GetSkinByName,
1910
+ GetSkinNameList,
1911
+ MatchGoalState,
1807
1912
  SIDE_MAX,
1808
1913
  SIDE_MIDDLE,
1809
1914
  SIDE_MIN,