easter-egg-quest 1.0.6 → 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.
|
|
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
|
|
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.
|
|
1418
|
-
|
|
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.
|
|
1430
|
-
|
|
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.
|
|
1442
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
);
|
|
@@ -3451,35 +3505,38 @@ const _ResultsRenderer = class _ResultsRenderer {
|
|
|
3451
3505
|
}
|
|
3452
3506
|
// ─── Combined copy & share ──────────────────────────────────────────
|
|
3453
3507
|
_copyShareImage(s) {
|
|
3508
|
+
var _a2;
|
|
3454
3509
|
const canvas = this._renderCard(s);
|
|
3455
|
-
canvas.
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
}
|
|
3470
|
-
}
|
|
3471
|
-
if (navigator.clipboard && typeof ClipboardItem !== "undefined") {
|
|
3472
|
-
navigator.clipboard.write([
|
|
3473
|
-
new ClipboardItem({ "image/png": blob })
|
|
3474
|
-
]).then(() => {
|
|
3475
|
-
this._flashButton(".eeq-btn-share", "copied!");
|
|
3510
|
+
const dataUrl = canvas.toDataURL("image/png");
|
|
3511
|
+
const byteString = atob(dataUrl.split(",")[1]);
|
|
3512
|
+
const ab = new ArrayBuffer(byteString.length);
|
|
3513
|
+
const ia = new Uint8Array(ab);
|
|
3514
|
+
for (let i = 0; i < byteString.length; i++) ia[i] = byteString.charCodeAt(i);
|
|
3515
|
+
const blob = new Blob([ab], { type: "image/png" });
|
|
3516
|
+
const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent) && window.innerWidth < 768;
|
|
3517
|
+
if (isMobile && navigator.share) {
|
|
3518
|
+
const file = new File([blob], "easter-egg-quest.png", { type: "image/png" });
|
|
3519
|
+
if ((_a2 = navigator.canShare) == null ? void 0 : _a2.call(navigator, { files: [file] })) {
|
|
3520
|
+
navigator.share({
|
|
3521
|
+
files: [file],
|
|
3522
|
+
title: "Easter Egg Quest",
|
|
3523
|
+
text: `«${s.behaviorProfile.title}»`
|
|
3476
3524
|
}).catch(() => {
|
|
3477
|
-
this._downloadBlob(blob);
|
|
3478
3525
|
});
|
|
3479
3526
|
return;
|
|
3480
3527
|
}
|
|
3481
|
-
|
|
3482
|
-
|
|
3528
|
+
}
|
|
3529
|
+
if (navigator.clipboard && typeof ClipboardItem !== "undefined") {
|
|
3530
|
+
navigator.clipboard.write([
|
|
3531
|
+
new ClipboardItem({ "image/png": blob })
|
|
3532
|
+
]).then(() => {
|
|
3533
|
+
this._flashButton(".eeq-btn-share", "copied!");
|
|
3534
|
+
}).catch(() => {
|
|
3535
|
+
this._downloadBlob(blob);
|
|
3536
|
+
});
|
|
3537
|
+
return;
|
|
3538
|
+
}
|
|
3539
|
+
this._downloadBlob(blob);
|
|
3483
3540
|
}
|
|
3484
3541
|
_downloadBlob(blob) {
|
|
3485
3542
|
const url = URL.createObjectURL(blob);
|
|
@@ -4960,7 +5017,8 @@ class GameController {
|
|
|
4960
5017
|
}
|
|
4961
5018
|
// ─── Stage Progress ────────────────────────────────────────────────────
|
|
4962
5019
|
_handleStageProgress(progress) {
|
|
4963
|
-
|
|
5020
|
+
const stage = this.fsm.state;
|
|
5021
|
+
if (this.threeRenderer && stage !== "stage3-active") {
|
|
4964
5022
|
this.threeRenderer.showProgressParticles(progress);
|
|
4965
5023
|
}
|
|
4966
5024
|
const now = Date.now();
|