danoniplus 46.7.0 → 47.0.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 : 2026/04/13
7
+ * Revised : 2026/04/20
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 46.7.0`;
12
- const g_revisedDate = `2026/04/13`;
11
+ const g_version = `Ver 47.0.1`;
12
+ const g_revisedDate = `2026/04/20`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -213,6 +213,9 @@ const g_detailObj = {
213
213
  speedData: [],
214
214
  boostData: [],
215
215
  toolDif: [],
216
+ scoreMinimap: {},
217
+ scoreMinimapReverse: {},
218
+ scoreMinimapHeader: {},
216
219
  };
217
220
 
218
221
  const g_workObj = {
@@ -3352,6 +3355,154 @@ const storeBaseData = (_scoreId, _scoreObj, _keyCtrlPtn) => {
3352
3355
  g_detailObj.startFrame[_scoreId] = startFrame;
3353
3356
  g_detailObj.playingFrame[_scoreId] = playingFrame;
3354
3357
  g_detailObj.playingFrameWithBlank[_scoreId] = lastFrame - startFrame;
3358
+
3359
+ const generateMinimap = (_scoreId, _scoreObj, _keyNum, _playingFrame, _firstArrowFrame, _isReverse = false) => {
3360
+ // 高さを演奏時間に比例させる (例: 1フレーム = 0.5px)
3361
+ const scale = 1.5;
3362
+ const dpr = window.devicePixelRatio || 1; // デバイスのピクセル比を取得(通常 2〜3)
3363
+
3364
+ const timeMargin = 35; // 時間表示用の左マージン
3365
+ const mmWidth = (g_sWidth - 500) / 2 + 290; // 基準となるコマの横幅(親divより少し短くする)
3366
+ const mmHeightTotal = _playingFrame * scale;
3367
+ const mmMarginY = 2;
3368
+ const laneWidth = Math.min(Math.floor((mmWidth - timeMargin) / _keyNum), 40);
3369
+ const logicalWidth = timeMargin + (laneWidth * _keyNum);
3370
+
3371
+ // ヘッダー用キャンバスの作成
3372
+ const canvasHeader = document.createElement(`canvas`);
3373
+ const ctxHeader = canvasHeader.getContext(`2d`);
3374
+ canvasHeader.width = logicalWidth * dpr;
3375
+ canvasHeader.height = 15 * dpr;
3376
+ canvasHeader.style.width = `${logicalWidth}px`;
3377
+ canvasHeader.style.height = `15px`;
3378
+ ctxHeader.scale(dpr, dpr);
3379
+ ctxHeader.fillStyle = '#999';
3380
+ ctxHeader.font = `10px ${getBasicFont()}`;
3381
+ ctxHeader.textAlign = 'center';
3382
+
3383
+ for (let j = 0; j < _keyNum; j++) {
3384
+ const x = timeMargin + j * laneWidth + laneWidth / 2;
3385
+ ctxHeader.fillText(g_kCd[g_keyObj[`keyCtrl${_keyCtrlPtn}`][j][0]], x, 10);
3386
+ ctxHeader.strokeStyle = '#444';
3387
+ }
3388
+
3389
+ g_detailObj.scoreMinimapHeader[_scoreId] = canvasHeader;
3390
+
3391
+ // 譜面全体のキャンバスの作成
3392
+ const MAX_CANVAS_HEIGHT = 10000; // 1枚あたりの高さ制限(安全圏)
3393
+ const canvasCount = Math.ceil((mmHeightTotal + mmMarginY * 2) / MAX_CANVAS_HEIGHT);
3394
+ const canvases = [];
3395
+
3396
+ for (let i = 0; i < canvasCount; i++) {
3397
+ const cvs = document.createElement('canvas');
3398
+ const h = (i === canvasCount - 1)
3399
+ ? (mmHeightTotal + mmMarginY * 2) - (MAX_CANVAS_HEIGHT * i)
3400
+ : MAX_CANVAS_HEIGHT;
3401
+
3402
+ cvs.width = logicalWidth * dpr;
3403
+ cvs.height = h * dpr;
3404
+ cvs.style.width = `${logicalWidth}px`;
3405
+ cvs.style.height = `${h}px`;
3406
+ cvs.style.display = 'block'; // 隙間防止
3407
+ const ctx = cvs.getContext('2d');
3408
+ ctx.scale(dpr, dpr);
3409
+ canvases.push({ canvas: cvs, ctx: ctx, offsetTop: i * MAX_CANVAS_HEIGHT });
3410
+ }
3411
+
3412
+ // --- 描画先を振り分けるヘルパー関数 ---
3413
+ const drawOnTarget = (y, height, drawFunc) => {
3414
+ canvases.forEach(item => {
3415
+ // 描画要素がCanvasの範囲内に入っているか判定
3416
+ if (y + height >= item.offsetTop && y <= item.offsetTop + (item.canvas.height / dpr)) {
3417
+ item.ctx.save();
3418
+ item.ctx.translate(0, -item.offsetTop);
3419
+ drawFunc(item.ctx);
3420
+ item.ctx.restore();
3421
+ }
3422
+ });
3423
+ };
3424
+
3425
+ // --- Y座標計算用の関数 ---
3426
+ // 通常:上(0)から下へ増える
3427
+ // リバース:最大値(mmHeight)から上へ向かって減る
3428
+ const getY = (frame) => {
3429
+ const relativeFrame = frame - _firstArrowFrame;
3430
+ const rawY = relativeFrame * scale;
3431
+ return _isReverse ? (mmHeightTotal - rawY + mmMarginY) : (rawY + mmMarginY);
3432
+ };
3433
+
3434
+ // 時間表記用のフォーマット関数
3435
+ const formatTime = (frame) => {
3436
+ const [m, s] = transFrameToTimer(frame).split(`:`);
3437
+ return `${m.padStart(2, `0`)}:${s}`;
3438
+ };
3439
+
3440
+ // --- 1. 時間軸・ガイドライン ---
3441
+ const interval = g_fps;
3442
+ let startPoint = Math.ceil(_firstArrowFrame / interval) * interval;
3443
+ for (let currentFrame = startPoint; currentFrame <= _firstArrowFrame + _playingFrame; currentFrame += interval) {
3444
+ const y = getY(currentFrame);
3445
+ drawOnTarget(y - 5, 10, (ctx) => {
3446
+ ctx.strokeStyle = '#444';
3447
+ ctx.fillStyle = '#999';
3448
+ ctx.font = `10px ${getBasicFont()}`;
3449
+ ctx.textAlign = 'right';
3450
+ ctx.textBaseline = 'middle';
3451
+ ctx.beginPath();
3452
+ ctx.moveTo(timeMargin, y);
3453
+ ctx.lineTo(timeMargin + laneWidth * _keyNum, y);
3454
+ ctx.stroke();
3455
+ ctx.fillText(formatTime(currentFrame), timeMargin, y);
3456
+ });
3457
+ }
3458
+
3459
+ // --- 2. フリーズノート ---
3460
+ for (let j = 0; j < _keyNum; j++) {
3461
+ const frz = _scoreObj.frzData[j];
3462
+ for (let k = 0; k < frz.length; k += 2) {
3463
+ const start = frz[k], end = frz[k + 1];
3464
+ if (isNaN(start) || isNaN(end)) continue;
3465
+ const y1 = getY(start), y2 = getY(end);
3466
+ const x = timeMargin + j * laneWidth;
3467
+ const top = Math.min(y1, y2), h = Math.abs(y2 - y1);
3468
+
3469
+ drawOnTarget(top, h, (ctx) => {
3470
+ ctx.fillStyle = 'rgba(0, 200, 255, 0.4)';
3471
+ ctx.fillRect(x + 2, top, laneWidth - 3, h);
3472
+ ctx.strokeStyle = 'rgba(0, 200, 255, 0.8)';
3473
+ ctx.strokeRect(x + 2, top, laneWidth - 3, h);
3474
+ });
3475
+ }
3476
+ }
3477
+
3478
+ // --- 3. 通常ノート ---
3479
+ for (let j = 0; j < _keyNum; j++) {
3480
+ const color = g_dfColorObj.setColorType2[g_keyObj[`color${_keyCtrlPtn}_0`][j]] || '#ffffff';
3481
+ _scoreObj.arrowData[j].forEach(note => {
3482
+ const val = parseFloat(note);
3483
+ if (isNaN(val)) return;
3484
+ const y = getY(val), x = timeMargin + j * laneWidth;
3485
+ drawOnTarget(y - 1.5, 3, (ctx) => {
3486
+ ctx.fillStyle = color;
3487
+ ctx.fillRect(x + 1, y - 1.5, laneWidth - 1, 3);
3488
+ });
3489
+ });
3490
+ }
3491
+
3492
+ // 保存(Canvasの配列を保存する)
3493
+ const result = canvases.map(item => item.canvas);
3494
+ if (_isReverse) {
3495
+ g_detailObj.scoreMinimapReverse[_scoreId] = result;
3496
+ } else {
3497
+ g_detailObj.scoreMinimap[_scoreId] = result;
3498
+ }
3499
+ };
3500
+
3501
+ // storeBaseData の中で呼び出す
3502
+ // 通常版を生成
3503
+ generateMinimap(_scoreId, _scoreObj, keyNum, playingFrame, firstArrowFrame, false);
3504
+ // リバース版を生成
3505
+ generateMinimap(_scoreId, _scoreObj, keyNum, playingFrame, firstArrowFrame, true);
3355
3506
  };
3356
3507
 
3357
3508
  /**
@@ -4393,8 +4544,8 @@ const headerConvert = _dosObj => {
4393
4544
  obj.playingLayout = g_presetObj.playingLayout ?? true;
4394
4545
  }
4395
4546
 
4396
- // ジャストフレームの設定 (ローカル: 0フレーム, リモートサーバ上: 1フレーム以内)
4397
- obj.justFrames = (g_isLocal) ? 0 : 1;
4547
+ // ジャストフレームの設定 (ローカル/デバッグ時: 0フレーム, 通常時: 1フレーム以内)
4548
+ obj.justFrames = g_isDebug ? 0 : 1;
4398
4549
 
4399
4550
  // リザルトデータのカスタマイズ
4400
4551
  obj.resultFormat = escapeHtmlForEnabledTag(_dosObj.resultFormat ?? g_presetObj.resultFormat ?? g_templateObj.resultFormatDf);
@@ -7580,6 +7731,73 @@ const makeHighScore = _scoreId => {
7580
7731
  }
7581
7732
  };
7582
7733
 
7734
+ const drawMinimap = (_scoreId, _initFlg = false) => {
7735
+ const detailMiniMap = document.getElementById(`detailMiniMap`);
7736
+ if (detailMiniMap === null) return; // scoreDetailUse=false 等で未生成の場合は何もしない
7737
+
7738
+ const currentScrollTop = document.getElementById(`detailMiniMapSub`)
7739
+ ? document.getElementById(`detailMiniMapSub`).scrollTop : 0;
7740
+
7741
+ // 再描画のため一度クリア
7742
+ deleteChildspriteAll(`detailMiniMap`);
7743
+
7744
+ // drawMinimap 内の Canvas 追加部分
7745
+ const savedCanvases = g_stateObj.miniMapRevFlg
7746
+ ? g_detailObj.scoreMinimapReverse[_scoreId]
7747
+ : g_detailObj.scoreMinimap[_scoreId];
7748
+
7749
+ // --- ヘッダー部分 ---
7750
+ const detailMiniMapHeader = createEmptySprite(detailMiniMap, `detailMiniMapHeader`, g_windowObj.detailMiniMapHeader);
7751
+ $id(`detailMiniMapHeader`).top = (g_stateObj.miniMapRevFlg ? 230 : 0) + `px`;
7752
+ detailMiniMapHeader.appendChild(g_detailObj.scoreMinimapHeader[_scoreId]);
7753
+
7754
+ // --- メイン(譜面)部分 ---
7755
+ const detailMiniMapSub = createEmptySprite(detailMiniMap, `detailMiniMapSub`, g_windowObj.detailMiniMapSub);
7756
+ $id(`detailMiniMapSub`).top = (g_stateObj.miniMapRevFlg ? 0 : 15) + `px`;
7757
+
7758
+ detailMiniMapSub.style.overflowX = 'hidden';
7759
+ detailMiniMapSub.style.overflowY = 'auto';
7760
+ detailMiniMapSub.style.pointerEvents = 'auto';
7761
+ detailMiniMapSub.style.display = 'block';
7762
+ detailMiniMapSub.style.textAlign = 'left';
7763
+
7764
+ if (savedCanvases && Array.isArray(savedCanvases)) {
7765
+ // 退避したCanvasそのものをDOMに追加(再描画不要で高速)
7766
+ detailMiniMapSub.style.overflow = C_DIS_AUTO;
7767
+ detailMiniMapSub.style.pointerEvents = C_DIS_AUTO;
7768
+ savedCanvases.forEach(canvas => {
7769
+ canvas.style.position = 'static';
7770
+ canvas.style.display = 'block';
7771
+ canvas.style.height = 'auto';
7772
+ detailMiniMapSub.appendChild(canvas);
7773
+ });
7774
+ }
7775
+ const scrollHeight = Math.max(detailMiniMapSub.scrollHeight - detailMiniMapSub.clientHeight, 0);
7776
+ const playingFrame = Math.max(g_detailObj.playingFrame[_scoreId], 1);
7777
+ const lastFrame = g_detailObj.startFrame[_scoreId] + g_detailObj.playingFrameWithBlank[_scoreId];
7778
+ const firstArrowFrame = lastFrame - g_detailObj.playingFrame[_scoreId];
7779
+ const fadeinFrameOffset = Math.max(0, Math.min(
7780
+ playingFrame,
7781
+ getStartFrame(lastFrame, g_stateObj.fadein, _scoreId) - firstArrowFrame
7782
+ ));
7783
+ const fadeinScrollTop = scrollHeight * fadeinFrameOffset / playingFrame;
7784
+ detailMiniMapSub.scrollTop = g_stateObj.miniMapRevFlg
7785
+ ? (_initFlg ? scrollHeight - currentScrollTop : scrollHeight - fadeinScrollTop)
7786
+ : (_initFlg ? scrollHeight - currentScrollTop : fadeinScrollTop);
7787
+
7788
+ if (document.getElementById(`lnkMiniMapRev`) === null) {
7789
+ scoreDetail.appendChild(
7790
+ makeDifLblCssButton(`lnkMiniMapRev`, g_lblNameObj.s_rev + `${g_stateObj.miniMapRevFlg ? `↑` : `↓`}`, 8, () => {
7791
+ g_stateObj.miniMapRevFlg = !g_stateObj.miniMapRevFlg;
7792
+ lnkMiniMapRev.textContent = g_lblNameObj.s_rev + `${g_stateObj.miniMapRevFlg ? `↑` : `↓`}`;
7793
+ drawMinimap(g_stateObj.scoreId, true);
7794
+ createScText(lnkMiniMapRev, `MiniMapRev`, { targetLabel: `lnkMiniMapRev`, x: -12 });
7795
+ }, g_lblPosObj.lnkMiniMapRev)
7796
+ );
7797
+ createScText(lnkMiniMapRev, `MiniMapRev`, { targetLabel: `lnkMiniMapRev`, x: -12 });
7798
+ }
7799
+ };
7800
+
7583
7801
  /**
7584
7802
  * 譜面初期化処理
7585
7803
  * - 譜面の基本設定(キー数、初期速度、リバース、ゲージ設定)をここで行う
@@ -7768,6 +7986,7 @@ const setDifficulty = (_initFlg) => {
7768
7986
  drawDensityGraph(g_stateObj.scoreId);
7769
7987
  makeDifInfo(g_stateObj.scoreId);
7770
7988
  makeHighScore(g_stateObj.scoreId);
7989
+ drawMinimap(g_stateObj.scoreId);
7771
7990
  }
7772
7991
 
7773
7992
  // 楽曲データの表示
@@ -7901,6 +8120,9 @@ const createOptionWindow = _sprite => {
7901
8120
 
7902
8121
  $id(`detail${g_stateObj.scoreDetail}`).visibility = `visible`;
7903
8122
  document.getElementById(`lnk${g_stateObj.scoreDetail}G`).classList.replace(g_cssObj.button_Default, g_cssObj.button_Setting);
8123
+
8124
+ document.getElementById(`lnkMiniMapRev`).style.display =
8125
+ g_stateObj.scoreDetail === `MiniMap` && g_stateObj.scoreDetailViewFlg ? C_DIS_INHERIT : C_DIS_NONE;
7904
8126
  };
7905
8127
 
7906
8128
  multiAppend(scoreDetail,
@@ -7908,6 +8130,7 @@ const createOptionWindow = _sprite => {
7908
8130
  createScoreDetail(`Density`),
7909
8131
  createScoreDetail(`ToolDif`, false),
7910
8132
  createScoreDetail(`HighScore`, false),
8133
+ createScoreDetail(`MiniMap`, false),
7911
8134
  );
7912
8135
  g_settings.scoreDetails.forEach((sd, j) => {
7913
8136
  scoreDetail.appendChild(
@@ -7943,6 +8166,8 @@ const createOptionWindow = _sprite => {
7943
8166
  if (_resetFlg) {
7944
8167
  g_shortcutObj.option.KeyQ.id = g_settings.scoreDetailCursors[0];
7945
8168
  }
8169
+ document.getElementById(`lnkMiniMapRev`).style.display =
8170
+ g_stateObj.scoreDetail === `MiniMap` && g_stateObj.scoreDetailViewFlg ? C_DIS_INHERIT : C_DIS_NONE;
7946
8171
  };
7947
8172
 
7948
8173
  // ---------------------------------------------------
@@ -8059,6 +8284,7 @@ const createOptionWindow = _sprite => {
8059
8284
  fadeinSlider.value = g_stateObj.fadein;
8060
8285
  lnkFadein.textContent = `${g_stateObj.fadein}${g_lblNameObj.percent}`;
8061
8286
  updateSettingSummary();
8287
+ drawMinimap(g_stateObj.scoreId);
8062
8288
  };
8063
8289
 
8064
8290
  multiAppend(spriteList.fadein,
@@ -8077,6 +8303,7 @@ const createOptionWindow = _sprite => {
8077
8303
  fadeinSlider.addEventListener(`input`, () => {
8078
8304
  g_stateObj.fadein = inputSlider(fadeinSlider, lnkFadein, `fadein`);
8079
8305
  updateSettingSummary();
8306
+ drawMinimap(g_stateObj.scoreId);
8080
8307
  }, false);
8081
8308
 
8082
8309
  // ---------------------------------------------------
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2026/04/13 (v46.7.0)
8
+ * Revised : 2026/04/19 (v47.0.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -213,6 +213,8 @@ const updateWindowSiz = () => {
213
213
  difFilter: { x: 0, y: 66, w: 140, h: 204 + g_sHeight - 500, overflow: C_DIS_AUTO, pointerEvents: C_DIS_AUTO },
214
214
  displaySprite: { x: 25, y: 30, w: (g_sWidth - 450) / 2, h: g_limitObj.setLblHeight * 5 },
215
215
  scoreDetail: { x: 20, y: 85, w: (g_sWidth - 500) / 2 + 420, h: 245, visibility: `hidden`, pointerEvents: C_DIS_AUTO },
216
+ detailMiniMapHeader: { x: 110, y: 0, w: (g_sWidth - 500) / 2 + 310, h: 15 },
217
+ detailMiniMapSub: { x: 110, y: 15, w: (g_sWidth - 500) / 2 + 310, h: 230, overflow: C_DIS_AUTO, pointerEvents: C_DIS_AUTO },
216
218
  detailObj: { w: (g_sWidth - 500) / 2 + 420, h: 230, visibility: `hidden` },
217
219
  keyconSprite: { y: 105, h: g_sHeight - 105, overflow: C_DIS_AUTO },
218
220
  loader: { y: g_sHeight - 10, h: 10, backgroundColor: `#333333` },
@@ -513,6 +515,9 @@ const updateWindowSiz = () => {
513
515
  btnSpdCursorR: {
514
516
  x: 100, y: 180, w: 15, h: 20, siz: 12,
515
517
  },
518
+ lnkMiniMapRev: {
519
+ w: g_limitObj.difCoverWidth, h: 20, borderStyle: `solid`,
520
+ },
516
521
 
517
522
  /** ディスプレイ画面 */
518
523
  scMsg: {
@@ -1170,6 +1175,7 @@ const g_stateObj = {
1170
1175
  scoreDetailViewFlg: false,
1171
1176
  scoreDetail: `Speed`,
1172
1177
  settingSummaryVisible: false,
1178
+ miniMapRevFlg: false,
1173
1179
 
1174
1180
  d_stepzone: C_FLG_ON,
1175
1181
  d_judgment: C_FLG_ON,
@@ -1329,7 +1335,7 @@ const g_settings = {
1329
1335
  opacitys: [10, 25, 50, 75, 100],
1330
1336
  opacityNum: 0,
1331
1337
 
1332
- scoreDetailDefs: [`Density`, `Speed`, `ToolDif`, `HighScore`],
1338
+ scoreDetailDefs: [`Density`, `Speed`, `ToolDif`, `HighScore`, `MiniMap`],
1333
1339
  scoreDetails: [],
1334
1340
  scoreDetailCursors: [],
1335
1341
 
@@ -2709,12 +2715,15 @@ const g_shortcutObj = {
2709
2715
  Digit2: { id: `lnkSpeedG` },
2710
2716
  Digit3: { id: `lnkToolDifG` },
2711
2717
  Digit4: { id: `lnkHighScoreG` },
2718
+ Digit5: { id: `lnkMiniMapG` },
2712
2719
  Numpad1: { id: `lnkDensityG` },
2713
2720
  Numpad2: { id: `lnkSpeedG` },
2714
2721
  Numpad3: { id: `lnkToolDifG` },
2715
2722
  Numpad4: { id: `lnkHighScoreG` },
2723
+ Numpad5: { id: `lnkMiniMapG` },
2716
2724
  KeyQ: { id: `lnkDensityG` },
2717
2725
  KeyP: { id: `lnkDifInfo` },
2726
+ KeyX: { id: `lnkMiniMapRev` },
2718
2727
  KeyZ: { id: `btnSave` },
2719
2728
  ControlLeft_KeyC: { id: `` },
2720
2729
  ControlRight_KeyC: { id: `` },
@@ -2745,12 +2754,15 @@ const g_shortcutObj = {
2745
2754
  Digit2: { id: `lnkSpeedG` },
2746
2755
  Digit3: { id: `lnkToolDifG` },
2747
2756
  Digit4: { id: `lnkHighScoreG` },
2757
+ Digit5: { id: `lnkMiniMapG` },
2748
2758
  Numpad1: { id: `lnkDensityG` },
2749
2759
  Numpad2: { id: `lnkSpeedG` },
2750
2760
  Numpad3: { id: `lnkToolDifG` },
2751
2761
  Numpad4: { id: `lnkHighScoreG` },
2762
+ Numpad5: { id: `lnkMiniMapG` },
2752
2763
  KeyQ: { id: `lnkDensityG` },
2753
2764
  KeyP: { id: `lnkDifInfo` },
2765
+ KeyX: { id: `lnkMiniMapRev` },
2754
2766
  ControlLeft_KeyC: { id: `` },
2755
2767
  ControlRight_KeyC: { id: `` },
2756
2768
  KeyC: { id: `lnkHighScore`, reset: true },
@@ -4433,6 +4445,8 @@ const g_lblNameObj = {
4433
4445
  s_arrow: `Arrow`,
4434
4446
  s_frz: `Frz`,
4435
4447
 
4448
+ s_rev: `MapScroll`,
4449
+
4436
4450
  d_StepZone: `StepZone`,
4437
4451
  d_Judgment: `Judgment`,
4438
4452
  d_FastSlow: `FastSlow`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "46.7.0",
3
+ "version": "47.0.1",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "./js/danoni_main.js",
6
6
  "jsdelivr": "./js/danoni_main.js",