danoniplus 35.2.1 → 35.4.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/js/danoni_main.js CHANGED
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2024/02/08
7
+ * Revised : 2024/02/23
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 35.2.1`;
12
- const g_revisedDate = `2024/02/08`;
11
+ const g_version = `Ver 35.4.1`;
12
+ const g_revisedDate = `2024/02/23`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -3729,9 +3729,9 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
3729
3729
  */
3730
3730
  const toSameValStr = _str => {
3731
3731
  const nums = _str?.split(`@:`);
3732
- const groupStr = nums[0].split(`!`).join(`,`);
3732
+ const groupStr = toFloatStr(nums[0]).split(`!`).join(`,`);
3733
3733
  return nums.length === 2 && !isNaN(parseInt(nums[1])) ?
3734
- [...Array(Math.floor(parseInt(nums[1])))].fill(groupStr).join(`,`) : _str;
3734
+ [...Array(Math.floor(parseInt(nums[1])))].fill(groupStr).join(`,`) : groupStr;
3735
3735
  };
3736
3736
 
3737
3737
  /**
@@ -3765,6 +3765,24 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
3765
3765
  return _num.startsWith(`b`) ? parseFloat(_num.slice(1)) + _divNum : parseFloat(_num);
3766
3766
  }
3767
3767
 
3768
+ /**
3769
+ * キーパターンの略名から実際のデータへ展開
3770
+ * @param {string} _str
3771
+ * @param {string} _name
3772
+ * @param {function} _convFunc
3773
+ */
3774
+ const expandKeyPtn = (_str, _name, _convFunc) => {
3775
+ const pos = _str.indexOf(`>`);
3776
+ const expandData = _ptnstr => structuredClone(g_keyObj[`${_name}${getKeyPtnName(_ptnstr)}`]) ?? [_convFunc(_ptnstr)];
3777
+
3778
+ if (pos > 0 && _name === `chara`) {
3779
+ const [header, ptn] = [_str.substring(0, pos), _str.substring(pos + 1)];
3780
+ return expandData(ptn)?.map(n => `${header}${n}`);
3781
+ } else {
3782
+ return expandData(_str);
3783
+ }
3784
+ };
3785
+
3768
3786
  /**
3769
3787
  * 新キー用複合パラメータ
3770
3788
  * @param {string} _key キー数
@@ -3788,9 +3806,7 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
3788
3806
  // |keyCtrl9j=Tab,7_0,Enter| -> |keyCtrl9j=Tab,S,D,F,Space,J,K,L,Enter| のように補完
3789
3807
  // |pos9j=0..4,6..9| -> |pos9j=0,1,2,3,4,6,7,8,9|
3790
3808
  g_keyObj[`${keyheader}_${k + dfPtn}`] =
3791
- toOriginalArray(tmpArray[k], toFloatStr).map(n =>
3792
- structuredClone(g_keyObj[`${_name}${getKeyPtnName(n)}`]) ?? [_convFunc(n)]
3793
- ).flat();
3809
+ toOriginalArray(tmpArray[k], toSameValStr).map(n => expandKeyPtn(n, _name, _convFunc)).flat();
3794
3810
  if (baseCopyFlg) {
3795
3811
  g_keyObj[`${keyheader}_${k + dfPtn}d`] = structuredClone(g_keyObj[`${keyheader}_${k + dfPtn}`]);
3796
3812
  }
@@ -3840,8 +3856,7 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
3840
3856
  // 部分的にキーパターン指定があった場合は既存パターンを展開 (例: |shuffle9j=2,7_0_0,2|)
3841
3857
  g_keyObj[`${keyheader}_${k + dfPtn}_${ptnCnt}`] =
3842
3858
  makeBaseArray(toOriginalArray(list, toSameValStr).map(n =>
3843
- structuredClone(g_keyObj[`${_name}${getKeyPtnName(n)}`]) ??
3844
- [isNaN(parseInt(n)) ? n : parseInt(n, 10)]
3859
+ expandKeyPtn(n, _name, _str => isNaN(parseInt(_str)) ? _str : parseInt(_str, 10))
3845
3860
  ).flat(), g_keyObj[`${g_keyObj.defaultProp}${_key}_${k + dfPtn}`].length, 0);
3846
3861
  ptnCnt++;
3847
3862
  }
@@ -3915,7 +3930,7 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
3915
3930
  // 部分的にキーパターン指定があった場合は既存パターンを展開 (例: |scroll9j=Cross::1,7_0,1|)
3916
3931
  const tmpParamPair = pairs.split(`::`);
3917
3932
  g_keyObj[pairName][tmpParamPair[0]] =
3918
- makeBaseArray(tmpParamPair[1]?.split(`,`).map(n =>
3933
+ makeBaseArray(toOriginalArray(tmpParamPair[1], toSameValStr)?.map(n =>
3919
3934
  structuredClone(g_keyObj[`${_pairName}${getKeyPtnName(n)}`]?.[tmpParamPair[0]]) ??
3920
3935
  [n === `-` ? -1 : parseInt(n, 10)]
3921
3936
  ).flat(), g_keyObj[`${g_keyObj.defaultProp}${_key}_${k + dfPtn}`].length, _defaultVal);
@@ -4007,6 +4022,9 @@ const keysConvert = (_dosObj, { keyExtraList = _dosObj.keyExtraList?.split(`,`)
4007
4022
  // 別キーフラグ (transKeyX_Y)
4008
4023
  newKeySingleParam(newKey, `transKey`, C_TYP_STRING, ``);
4009
4024
 
4025
+ // フラットモード (flatModeX_Y)
4026
+ newKeySingleParam(newKey, `flatMode`, C_TYP_BOOLEAN, false);
4027
+
4010
4028
  // シャッフルグループ (shuffleX_Y)
4011
4029
  newKeyTripleParam(newKey, `shuffle`);
4012
4030
 
@@ -6002,28 +6020,63 @@ const createSettingsDisplayWindow = _sprite => {
6002
6020
  const makeDisplayButton = (_name, _heightPos, _widthPos) => {
6003
6021
 
6004
6022
  const flg = g_stateObj[`d_${_name.toLowerCase()}`];
6005
- const list = [C_FLG_OFF, C_FLG_ON];
6006
6023
  const linkId = `lnk${_name}`;
6007
6024
 
6008
6025
  if (g_headerObj[`${_name}Use`]) {
6009
- const switchDisplay = evt => {
6010
- const displayFlg = g_stateObj[`d_${_name.toLowerCase()}`];
6011
- const displayNum = list.findIndex(flg => flg === displayFlg);
6012
- const nextDisplayFlg = list[(displayNum + 1) % list.length];
6013
- g_stateObj[`d_${_name.toLowerCase()}`] = nextDisplayFlg;
6014
- evt.target.classList.replace(g_cssObj[`button_${displayFlg}`], g_cssObj[`button_${nextDisplayFlg}`]);
6015
6026
 
6016
- interlockingButton(g_headerObj, _name, nextDisplayFlg, displayFlg, true);
6017
- }
6027
+ // 設定名、CSS名(2種)、表示名
6028
+ const list = [C_FLG_OFF, C_FLG_ON].concat(g_settings[`d_${_name}s`] || []);
6029
+ const cssBarList = [C_FLG_OFF, C_FLG_ON].concat(Array(g_settings[`d_${_name}s`]?.length).fill(g_settings.d_cssBarExName) || []);
6030
+ const cssBgList = [g_settings.d_cssBgName, g_settings.d_cssBgName].concat(Array(g_settings[`d_${_name}s`]?.length).fill(g_settings.d_cssBgExName) || []);
6031
+ const lbls = [toCapitalize(_name), toCapitalize(_name)].concat(g_settings[`d_${_name}s`] || []);
6032
+
6033
+ const dispView = _ => [C_FLG_OFF, C_FLG_ON].includes(g_stateObj[`d_${_name.toLowerCase()}`]) ?
6034
+ g_lblNameObj[`d_${toCapitalize(_name)}`] : getStgDetailName(lbls[g_settings.displayNum[_name]]);
6035
+
6036
+ const withShortCutDesc = _ => createScText(document.getElementById(linkId), `${toCapitalize(_name)}`,
6037
+ { displayName: g_currentPage, targetLabel: linkId, x: -5 });
6038
+
6039
+ /**
6040
+ * Displayボタン処理
6041
+ * @param {number} _scrollNum
6042
+ * @param {boolean} _filterFlg
6043
+ */
6044
+ const switchDisplay = (_scrollNum = 1, _filterFlg = true) => {
6045
+ const prevDisp = g_settings.displayNum[_name];
6046
+ const [prevBarColor, prevBgColor] = [cssBarList[prevDisp], cssBgList[prevDisp]];
6047
+
6048
+ g_settings.displayNum[_name] = (prevDisp + _scrollNum) % (_filterFlg ? 2 : list.length);
6049
+ const nextDisp = g_settings.displayNum[_name];
6050
+ const [nextBarColor, nextBgColor] = [cssBarList[nextDisp], cssBgList[nextDisp]];
6051
+
6052
+ g_stateObj[`d_${_name.toLowerCase()}`] = list[g_settings.displayNum[_name]];
6053
+ document.getElementById(linkId).innerHTML = dispView();
6054
+ document.getElementById(linkId).classList.replace(g_cssObj[`button_${prevBarColor}`], g_cssObj[`button_${nextBarColor}`]);
6055
+ document.getElementById(linkId).classList.replace(g_cssObj[`button_${prevBgColor}`], g_cssObj[`button_${nextBgColor}`]);
6056
+
6057
+ withShortCutDesc();
6058
+ interlockingButton(g_headerObj, _name, nextBarColor, prevBarColor, true);
6059
+ };
6060
+
6061
+ // Displayボタン初期化
6062
+ g_settings.displayNum[_name] = list.findIndex(flg => flg === g_stateObj[`d_${_name.toLowerCase()}`]);
6018
6063
  displaySprite.appendChild(
6019
- makeSettingLblCssButton(linkId, g_lblNameObj[`d_${toCapitalize(_name)}`], _heightPos, evt => switchDisplay(evt), {
6064
+ makeSettingLblCssButton(linkId, dispView(), _heightPos, _ => switchDisplay(), {
6020
6065
  x: 30 + 180 * _widthPos, w: 170,
6021
6066
  title: g_msgObj[`d_${_name.toLowerCase()}`], borderStyle: `solid`,
6022
- cxtFunc: evt => switchDisplay(evt),
6023
- }, `button_${flg}`)
6067
+ cxtFunc: _ => switchDisplay(-1),
6068
+ }, `button_${cssBgList[g_settings.displayNum[_name]]}`, `button_${cssBarList[g_settings.displayNum[_name]]}`)
6024
6069
  );
6025
- createScText(document.getElementById(linkId), `${toCapitalize(_name)}`,
6026
- { displayName: g_currentPage, targetLabel: linkId, x: -5 });
6070
+ withShortCutDesc();
6071
+
6072
+ // Display切替ボタン(ON/OFF以外用)
6073
+ if (g_settings[`d_${_name}s`] !== undefined) {
6074
+ displaySprite.appendChild(
6075
+ makeSettingLblCssButton(`${linkId}R`, `>`, _heightPos, _ => switchDisplay(1, false), {
6076
+ x: 175 + 180 * _widthPos, w: 25,
6077
+ }, g_cssObj.button_Mini)
6078
+ );
6079
+ }
6027
6080
  } else {
6028
6081
  displaySprite.appendChild(
6029
6082
  createDivCss2Label(linkId, g_lblNameObj[`d_${toCapitalize(_name)}`] + `:${g_headerObj[`${_name}Set`]}`, {
@@ -8819,7 +8872,8 @@ const mainInit = _ => {
8819
8872
  let speedCnts = 0;
8820
8873
  let boostCnts = 0;
8821
8874
  let keychCnts = 0;
8822
- const stepZoneDisp = (g_stateObj.d_stepzone === C_FLG_OFF || g_settings.scrollFlat.includes(g_stateObj.scroll)) ? C_DIS_NONE : C_DIS_INHERIT;
8875
+ const flatMode = g_stateObj.d_stepzone === `FlatBar` || g_stateObj.scroll.endsWith(`Flat`) || g_keyObj[`flatMode${keyCtrlPtn}`];
8876
+ const stepZoneDisp = (g_stateObj.d_stepzone === C_FLG_OFF || flatMode) ? C_DIS_NONE : C_DIS_INHERIT;
8823
8877
 
8824
8878
  for (let j = 0; j < keyNum; j++) {
8825
8879
  const colorPos = g_keyObj[`color${keyCtrlPtn}`][j];
@@ -8862,17 +8916,22 @@ const mainInit = _ => {
8862
8916
 
8863
8917
  );
8864
8918
  }
8865
- if (g_settings.scrollFlat.includes(g_stateObj.scroll) && g_stateObj.d_stepzone === C_FLG_ON) {
8919
+ if (flatMode && g_stateObj.d_stepzone !== C_FLG_OFF) {
8866
8920
 
8867
8921
  // スクロール名に`R-`が含まれていればリバースと見做す
8868
8922
  const reverseFlg = g_stateObj.reverse === C_FLG_ON || g_stateObj.scroll.startsWith(`R-`);
8869
8923
 
8870
8924
  // ステップゾーンの代わり
8871
8925
  const lineY = [(C_ARW_WIDTH - g_stateObj.flatStepHeight) / 2, (C_ARW_WIDTH + g_stateObj.flatStepHeight) / 2];
8926
+ const reverses = [reverseFlg, reverseFlg];
8927
+ if (makeDedupliArray(g_workObj.scrollDir).length > 1) {
8928
+ lineY.push(lineY[0], lineY[1]);
8929
+ reverses.push(!reverses[0], !reverses[1]);
8930
+ }
8872
8931
  lineY.forEach((y, j) => {
8873
8932
  mainSprite.appendChild(
8874
8933
  createColorObject2(`stepBar${j}`, {
8875
- x: 0, y: C_STEP_Y + g_posObj.reverseStepY * Number(reverseFlg) + y,
8934
+ x: 0, y: C_STEP_Y + g_posObj.reverseStepY * Number(reverses[j]) + y,
8876
8935
  w: g_headerObj.playingWidth - 50, h: 1, styleName: `lifeBar`,
8877
8936
  }, g_cssObj.life_Failed)
8878
8937
  );
@@ -10701,7 +10760,8 @@ const resultInit = _ => {
10701
10760
  ].filter(value => value !== ``).join(`, `);
10702
10761
 
10703
10762
  let displayData = [
10704
- withOptions(g_stateObj.d_stepzone, C_FLG_ON, g_lblNameObj.rd_StepZone),
10763
+ withOptions(g_stateObj.d_stepzone, C_FLG_ON, g_lblNameObj.rd_StepZone +
10764
+ `${g_stateObj.d_stepzone === C_FLG_OFF ? `` : ` : ${g_stateObj.d_stepzone}`}`),
10705
10765
  withOptions(g_stateObj.d_judgment, C_FLG_ON, g_lblNameObj.rd_Judgment),
10706
10766
  withOptions(g_stateObj.d_fastslow, C_FLG_ON, g_lblNameObj.rd_FastSlow),
10707
10767
  withOptions(g_stateObj.d_lifegauge, C_FLG_ON, g_lblNameObj.rd_LifeGauge),
@@ -10712,7 +10772,10 @@ const resultInit = _ => {
10712
10772
  if (displayData === ``) {
10713
10773
  displayData = `All Visible`;
10714
10774
  } else {
10715
- displayData += ` : OFF`;
10775
+ if (!displayData.includes(`,`) && g_stateObj.d_stepzone !== C_FLG_OFF) {
10776
+ } else {
10777
+ displayData += ` : OFF`;
10778
+ }
10716
10779
  }
10717
10780
 
10718
10781
  let display2Data = [
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2024/02/08 (v35.2.1)
8
+ * Revised : 2024/02/23 (v35.4.1)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -906,7 +906,6 @@ const g_settings = {
906
906
 
907
907
  scrolls: [],
908
908
  scrollNum: 0,
909
- scrollFlat: [`Flat`, `R-Flat`],
910
909
 
911
910
  shuffles: [C_FLG_OFF, `Mirror`, `X-Mirror`, `Turning`, `Random`, `Random+`, `S-Random`, `S-Random+`],
912
911
  shuffleNum: 0,
@@ -944,6 +943,29 @@ const g_settings = {
944
943
  scoreDetailCursors: [],
945
944
 
946
945
  scoreDetailTrans: [[`Velocity`, `Speed`], [`DifLevel`, `ToolDif`]],
946
+
947
+ // Display設定の拡張用デザイン
948
+ d_cssBarExName: `RevON`,
949
+ d_cssBgName: `Default`,
950
+ d_cssBgExName: `Setting`,
951
+
952
+ // Display設定の拡張リスト
953
+ d_stepZones: [`FlatBar`],
954
+
955
+ displayNum: {
956
+ stepZone: 0,
957
+ judgment: 0,
958
+ fastSlow: 0,
959
+ lifeGauge: 0,
960
+ score: 0,
961
+ musicInfo: 0,
962
+ speed: 0,
963
+ color: 0,
964
+ lyrics: 0,
965
+ background: 0,
966
+ arrowEffect: 0,
967
+ special: 0,
968
+ },
947
969
  };
948
970
 
949
971
  g_settings.volumeNum = g_settings.volumes.length - 1;
@@ -1542,6 +1564,33 @@ const g_shortcutObj = {
1542
1564
  ShiftRight_KeyT: { id: `lnkHitPositionL` },
1543
1565
  KeyT: { id: `lnkHitPositionLL` },
1544
1566
 
1567
+ ShiftLeft_Digit1: { id: `lnkstepZoneR` },
1568
+ ShiftRight_Digit1: { id: `lnkstepZoneR` },
1569
+ ShiftLeft_Digit2: { id: `lnkjudgmentR` },
1570
+ ShiftRight_Digit2: { id: `lnkjudgmentR` },
1571
+ ShiftLeft_Digit3: { id: `lnkfastSlowR` },
1572
+ ShiftRight_Digit3: { id: `lnkfastSlowR` },
1573
+ ShiftLeft_Digit4: { id: `lnklifeGaugeR` },
1574
+ ShiftRight_Digit4: { id: `lnklifeGaugeR` },
1575
+ ShiftLeft_Digit5: { id: `lnkscoreR` },
1576
+ ShiftRight_Digit5: { id: `lnkscoreR` },
1577
+ ShiftLeft_Digit6: { id: `lnkmusicInfoR` },
1578
+ ShiftRight_Digit6: { id: `lnkmusicInfoR` },
1579
+ ShiftLeft_Digit7: { id: `lnkfilterLineR` },
1580
+ ShiftRight_Digit7: { id: `lnkfilterLineR` },
1581
+ ShiftLeft_Digit8: { id: `lnkspeedR` },
1582
+ ShiftRight_Digit8: { id: `lnkspeedR` },
1583
+ ShiftLeft_Digit9: { id: `lnkcolorR` },
1584
+ ShiftRight_Digit9: { id: `lnkcolorR` },
1585
+ ShiftLeft_Digit0: { id: `lnklyricsR` },
1586
+ ShiftRight_Digit0: { id: `lnklyricsR` },
1587
+ ShiftLeft_Semicolon: { id: `lnkbackgroundR` },
1588
+ ShiftRight_Semicolon: { id: `lnkbackgroundR` },
1589
+ ShiftLeft_Minus: { id: `lnkarrowEffectR` },
1590
+ ShiftRight_Minus: { id: `lnkarrowEffectR` },
1591
+ ShiftLeft_Slash: { id: `lnkspecialR` },
1592
+ ShiftRight_Slash: { id: `lnkspecialR` },
1593
+
1545
1594
  Digit1: { id: `lnkstepZone` },
1546
1595
  Digit2: { id: `lnkjudgment` },
1547
1596
  Digit3: { id: `lnkfastSlow` },
@@ -1556,6 +1605,33 @@ const g_shortcutObj = {
1556
1605
  Minus: { id: `lnkarrowEffect` },
1557
1606
  Slash: { id: `lnkspecial` },
1558
1607
 
1608
+ ShiftLeft_Numpad1: { id: `lnkstepZoneR` },
1609
+ ShiftRight_Numpad1: { id: `lnkstepZoneR` },
1610
+ ShiftLeft_Numpad2: { id: `lnkjudgmentR` },
1611
+ ShiftRight_Numpad2: { id: `lnkjudgmentR` },
1612
+ ShiftLeft_Numpad3: { id: `lnkfastSlowR` },
1613
+ ShiftRight_Numpad3: { id: `lnkfastSlowR` },
1614
+ ShiftLeft_Numpad4: { id: `lnklifeGaugeR` },
1615
+ ShiftRight_Numpad4: { id: `lnklifeGaugeR` },
1616
+ ShiftLeft_Numpad5: { id: `lnkscoreR` },
1617
+ ShiftRight_Numpad5: { id: `lnkscoreR` },
1618
+ ShiftLeft_Numpad6: { id: `lnkmusicInfoR` },
1619
+ ShiftRight_Numpad6: { id: `lnkmusicInfoR` },
1620
+ ShiftLeft_Numpad7: { id: `lnkfilterLineR` },
1621
+ ShiftRight_Numpad7: { id: `lnkfilterLineR` },
1622
+ ShiftLeft_Numpad8: { id: `lnkspeedR` },
1623
+ ShiftRight_Numpad8: { id: `lnkspeedR` },
1624
+ ShiftLeft_Numpad9: { id: `lnkcolorR` },
1625
+ ShiftRight_Numpad9: { id: `lnkcolorR` },
1626
+ ShiftLeft_Numpad0: { id: `lnklyricsR` },
1627
+ ShiftRight_Numpad0: { id: `lnklyricsR` },
1628
+ ShiftLeft_NumpadAdd: { id: `lnkbackgroundR` },
1629
+ ShiftRight_NumpadAdd: { id: `lnkbackgroundR` },
1630
+ ShiftLeft_NumpadSubtract: { id: `lnkarrowEffectR` },
1631
+ ShiftRight_NumpadSubtract: { id: `lnkarrowEffectR` },
1632
+ ShiftLeft_NumpadDivide: { id: `lnkspecialR` },
1633
+ ShiftRight_NumpadDivide: { id: `lnkspecialR` },
1634
+
1559
1635
  Numpad1: { id: `lnkstepZone` },
1560
1636
  Numpad2: { id: `lnkjudgment` },
1561
1637
  Numpad3: { id: `lnkfastSlow` },
@@ -2801,7 +2877,7 @@ const g_lblNameObj = {
2801
2877
  d_Score: `Score`,
2802
2878
  d_MusicInfo: `MusicInfo`,
2803
2879
  d_FilterLine: `FilterLine`,
2804
- d_Speed: `Speed`,
2880
+ d_Speed: `Velocity`,
2805
2881
  d_Color: `Color`,
2806
2882
  d_Lyrics: `Lyrics`,
2807
2883
  d_Background: `Background`,
@@ -2857,6 +2933,8 @@ const g_lblNameObj = {
2857
2933
  'u_Hard': `Hard`,
2858
2934
  'u_Easy': `Easy`,
2859
2935
 
2936
+ 'u_FlatBar': `FlatBar`,
2937
+
2860
2938
  'u_Visible': `Visible`,
2861
2939
  'u_Hidden': `Hidden`,
2862
2940
  'u_Hidden+': `Hidden+`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "35.2.1",
3
+ "version": "35.4.1",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "index.js",
6
6
  "scripts": {