easter-egg-quest 1.0.7 → 1.0.8

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.
@@ -1365,8 +1365,39 @@ class ThreeRenderer {
1365
1365
  this._collectFlashOpacity = 0;
1366
1366
  this._collectShake = 0;
1367
1367
  this._collectCamBaseZ = 5;
1368
+ this._finaleInteractive = false;
1369
+ this._finaleDragTarget = null;
1370
+ this._finalePausedRotation = [false, false, false];
1368
1371
  this._onPointerDown = (e) => {
1369
- if (this._interactiveEgg === null || this._disposed) return;
1372
+ if (this._disposed) return;
1373
+ if (this._finaleInteractive && this._finaleActive) {
1374
+ let bestIdx = -1;
1375
+ let bestDist = Infinity;
1376
+ for (let i = 0; i < 3; i++) {
1377
+ const egg3 = this.eggs[i];
1378
+ if (!egg3 || !egg3.visible) continue;
1379
+ const scr = this._worldToScreen(egg3.position);
1380
+ const d = Math.sqrt((e.clientX - scr.x) ** 2 + (e.clientY - scr.y) ** 2);
1381
+ if (d < bestDist) {
1382
+ bestDist = d;
1383
+ bestIdx = i;
1384
+ }
1385
+ }
1386
+ if (bestIdx < 0 || bestDist > 140) return;
1387
+ e.preventDefault();
1388
+ e.stopPropagation();
1389
+ this._finaleDragTarget = bestIdx;
1390
+ this._isDragging = true;
1391
+ this._dragMoved = false;
1392
+ this._dragStartX = e.clientX;
1393
+ this._dragStartY = e.clientY;
1394
+ const egg2 = this.eggs[bestIdx];
1395
+ this._dragRotX = egg2.rotation.x;
1396
+ this._dragRotY = egg2.rotation.y;
1397
+ document.body.style.cursor = "grabbing";
1398
+ return;
1399
+ }
1400
+ if (this._interactiveEgg === null) return;
1370
1401
  const egg = this.eggs[this._interactiveEgg];
1371
1402
  if (!egg || !egg.visible) return;
1372
1403
  const eggScreen = this._worldToScreen(egg.position);
@@ -1388,7 +1419,22 @@ class ThreeRenderer {
1388
1419
  this._holdProgress = 0;
1389
1420
  };
1390
1421
  this._onPointerMove = (e) => {
1391
- if (!this._isDragging || this._interactiveEgg === null) return;
1422
+ if (!this._isDragging) return;
1423
+ if (this._finaleDragTarget !== null) {
1424
+ e.preventDefault();
1425
+ e.stopPropagation();
1426
+ const egg2 = this.eggs[this._finaleDragTarget];
1427
+ if (!egg2) return;
1428
+ const dx2 = e.clientX - this._dragStartX;
1429
+ const dy2 = e.clientY - this._dragStartY;
1430
+ egg2.rotation.y = this._dragRotY + dx2 * 8e-3;
1431
+ egg2.rotation.x = this._dragRotX + dy2 * 5e-3;
1432
+ if (Math.abs(dx2) > 5 || Math.abs(dy2) > 5) {
1433
+ this._finalePausedRotation[this._finaleDragTarget] = true;
1434
+ }
1435
+ return;
1436
+ }
1437
+ if (this._interactiveEgg === null) return;
1392
1438
  e.preventDefault();
1393
1439
  e.stopPropagation();
1394
1440
  const egg = this.eggs[this._interactiveEgg];
@@ -1408,43 +1454,29 @@ class ThreeRenderer {
1408
1454
  e.stopPropagation();
1409
1455
  }
1410
1456
  this._isDragging = false;
1457
+ this._finaleDragTarget = null;
1411
1458
  this._cancelLongPress();
1412
- if (this._interactiveEgg !== null) {
1459
+ if (this._interactiveEgg !== null || this._finaleInteractive) {
1413
1460
  document.body.style.cursor = "grab";
1414
1461
  }
1415
1462
  };
1416
1463
  this._onWheel = (e) => {
1417
- if (this._interactiveEgg === null || this._disposed) return;
1418
- const egg = this.eggs[this._interactiveEgg];
1419
- if (!egg || !egg.visible) return;
1420
- const eggScreen = this._worldToScreen(egg.position);
1421
- const dx = e.clientX - eggScreen.x;
1422
- const dy = e.clientY - eggScreen.y;
1423
- if (Math.sqrt(dx * dx + dy * dy) <= 120) {
1464
+ if (this._disposed) return;
1465
+ if (this._isPointerNearAnyEgg(e.clientX, e.clientY)) {
1424
1466
  e.preventDefault();
1425
1467
  e.stopPropagation();
1426
1468
  }
1427
1469
  };
1428
1470
  this._onClickCapture = (e) => {
1429
- if (this._interactiveEgg === null || this._disposed) return;
1430
- const egg = this.eggs[this._interactiveEgg];
1431
- if (!egg || !egg.visible) return;
1432
- const eggScreen = this._worldToScreen(egg.position);
1433
- const dx = e.clientX - eggScreen.x;
1434
- const dy = e.clientY - eggScreen.y;
1435
- if (Math.sqrt(dx * dx + dy * dy) <= 120) {
1471
+ if (this._disposed) return;
1472
+ if (this._isPointerNearAnyEgg(e.clientX, e.clientY)) {
1436
1473
  e.preventDefault();
1437
1474
  e.stopPropagation();
1438
1475
  }
1439
1476
  };
1440
1477
  this._onMouseDownCapture = (e) => {
1441
- if (this._interactiveEgg === null || this._disposed) return;
1442
- const egg = this.eggs[this._interactiveEgg];
1443
- if (!egg || !egg.visible) return;
1444
- const eggScreen = this._worldToScreen(egg.position);
1445
- const dx = e.clientX - eggScreen.x;
1446
- const dy = e.clientY - eggScreen.y;
1447
- if (Math.sqrt(dx * dx + dy * dy) <= 120) {
1478
+ if (this._disposed) return;
1479
+ if (this._isPointerNearAnyEgg(e.clientX, e.clientY)) {
1448
1480
  e.preventDefault();
1449
1481
  e.stopPropagation();
1450
1482
  }
@@ -1456,15 +1488,10 @@ class ThreeRenderer {
1456
1488
  }
1457
1489
  };
1458
1490
  this._onTouchStartCapture = (e) => {
1459
- if (this._interactiveEgg === null || this._disposed) return;
1460
- const egg = this.eggs[this._interactiveEgg];
1461
- if (!egg || !egg.visible) return;
1491
+ if (this._disposed) return;
1462
1492
  const touch = e.touches[0];
1463
1493
  if (!touch) return;
1464
- const eggScreen = this._worldToScreen(egg.position);
1465
- const dx = touch.clientX - eggScreen.x;
1466
- const dy = touch.clientY - eggScreen.y;
1467
- if (Math.sqrt(dx * dx + dy * dy) <= 120) {
1494
+ if (this._isPointerNearAnyEgg(touch.clientX, touch.clientY)) {
1468
1495
  e.preventDefault();
1469
1496
  e.stopPropagation();
1470
1497
  }
@@ -1578,6 +1605,8 @@ class ThreeRenderer {
1578
1605
  disableInteraction() {
1579
1606
  this._interactiveEgg = null;
1580
1607
  this._isDragging = false;
1608
+ this._finaleDragTarget = null;
1609
+ this._finaleInteractive = false;
1581
1610
  this._cancelLongPress();
1582
1611
  document.body.style.cursor = "";
1583
1612
  }
@@ -1720,6 +1749,10 @@ class ThreeRenderer {
1720
1749
  this._finaleActive = true;
1721
1750
  this._finaleT = 0;
1722
1751
  this.disableInteraction();
1752
+ this._finaleInteractive = true;
1753
+ this._finaleDragTarget = null;
1754
+ this._finalePausedRotation = [false, false, false];
1755
+ document.body.style.cursor = "grab";
1723
1756
  for (let i = 0; i < 3; i++) {
1724
1757
  const state = this._eggStates[i];
1725
1758
  state.phase = "finale";
@@ -2594,6 +2627,25 @@ class ThreeRenderer {
2594
2627
  y: (-v.y * 0.5 + 0.5) * window.innerHeight
2595
2628
  };
2596
2629
  }
2630
+ /** Check if pointer is near any active egg (interactive or finale). */
2631
+ _isPointerNearAnyEgg(px, py) {
2632
+ if (this._finaleInteractive) {
2633
+ for (let i = 0; i < 3; i++) {
2634
+ const egg2 = this.eggs[i];
2635
+ if (!egg2 || !egg2.visible) continue;
2636
+ const scr2 = this._worldToScreen(egg2.position);
2637
+ const d2 = Math.sqrt((px - scr2.x) ** 2 + (py - scr2.y) ** 2);
2638
+ if (d2 <= 140) return true;
2639
+ }
2640
+ return false;
2641
+ }
2642
+ if (this._interactiveEgg === null) return false;
2643
+ const egg = this.eggs[this._interactiveEgg];
2644
+ if (!egg || !egg.visible) return false;
2645
+ const scr = this._worldToScreen(egg.position);
2646
+ const d = Math.sqrt((px - scr.x) ** 2 + (py - scr.y) ** 2);
2647
+ return d <= 120;
2648
+ }
2597
2649
  _screenToWorld(sx, sy) {
2598
2650
  const T = this.THREE;
2599
2651
  const ndcX = sx / window.innerWidth * 2 - 1;
@@ -2780,7 +2832,9 @@ class ThreeRenderer {
2780
2832
  group.position.x += (tx - group.position.x) * 0.06;
2781
2833
  group.position.y += (ty - group.position.y) * 0.06;
2782
2834
  group.position.z += (tz - group.position.z) * 0.06;
2783
- group.rotation.y = this._finaleT * 0.4 + i * (Math.PI * 2 / 3);
2835
+ if (!this._finalePausedRotation[i]) {
2836
+ group.rotation.y = this._finaleT * 0.4 + i * (Math.PI * 2 / 3);
2837
+ }
2784
2838
  group.scale.setScalar(
2785
2839
  group.scale.x + (eggScale - group.scale.x) * 0.04
2786
2840
  );
@@ -4963,7 +5017,8 @@ class GameController {
4963
5017
  }
4964
5018
  // ─── Stage Progress ────────────────────────────────────────────────────
4965
5019
  _handleStageProgress(progress) {
4966
- if (this.threeRenderer) {
5020
+ const stage = this.fsm.state;
5021
+ if (this.threeRenderer && stage !== "stage3-active") {
4967
5022
  this.threeRenderer.showProgressParticles(progress);
4968
5023
  }
4969
5024
  const now = Date.now();