easter-egg-quest 1.0.12 โ 1.0.14
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.
|
@@ -141,19 +141,21 @@ function resolveConfig(raw = {}) {
|
|
|
141
141
|
theme,
|
|
142
142
|
hiddenEntry: {
|
|
143
143
|
mode: ((_b2 = raw.hiddenEntry) == null ? void 0 : _b2.mode) ?? "auto",
|
|
144
|
-
selector: (_c = raw.hiddenEntry) == null ? void 0 : _c.selector,
|
|
144
|
+
selector: sanitizeSelector((_c = raw.hiddenEntry) == null ? void 0 : _c.selector),
|
|
145
145
|
excludeSelectors: [
|
|
146
146
|
...DEFAULT_EXCLUDE_SELECTORS,
|
|
147
|
-
...((_d = raw.hiddenEntry) == null ? void 0 : _d.excludeSelectors) ?? []
|
|
147
|
+
...(((_d = raw.hiddenEntry) == null ? void 0 : _d.excludeSelectors) ?? []).filter(
|
|
148
|
+
(s) => typeof s === "string" && s.length < 200
|
|
149
|
+
)
|
|
148
150
|
]
|
|
149
151
|
},
|
|
150
152
|
hud: typeof raw.hud === "boolean" ? { enabled: raw.hud, position: "top-left" } : { enabled: ((_e = raw.hud) == null ? void 0 : _e.enabled) ?? true, position: ((_f = raw.hud) == null ? void 0 : _f.position) ?? "top-left" },
|
|
151
153
|
shrine: typeof raw.shrine === "boolean" ? { enabled: raw.shrine, position: "bottom-right" } : { enabled: ((_g = raw.shrine) == null ? void 0 : _g.enabled) ?? true, position: ((_h = raw.shrine) == null ? void 0 : _h.position) ?? "bottom-right" },
|
|
152
154
|
sounds: raw.sounds ?? false,
|
|
153
155
|
stageDurations: {
|
|
154
|
-
stillnessMs: ((_i = raw.stageDurations) == null ? void 0 : _i.stillnessMs
|
|
155
|
-
motionMs: ((_j = raw.stageDurations) == null ? void 0 : _j.motionMs
|
|
156
|
-
rhythmCycles: ((_k = raw.stageDurations) == null ? void 0 : _k.rhythmCycles
|
|
156
|
+
stillnessMs: clampDuration((_i = raw.stageDurations) == null ? void 0 : _i.stillnessMs, 2e4),
|
|
157
|
+
motionMs: clampDuration((_j = raw.stageDurations) == null ? void 0 : _j.motionMs, 2e4),
|
|
158
|
+
rhythmCycles: clampInt((_k = raw.stageDurations) == null ? void 0 : _k.rhythmCycles, 6, 1, 50)
|
|
157
159
|
},
|
|
158
160
|
renderer: raw.renderer ?? "auto",
|
|
159
161
|
scoring: {
|
|
@@ -169,11 +171,48 @@ function resolveConfig(raw = {}) {
|
|
|
169
171
|
callbacks: raw.callbacks ?? {}
|
|
170
172
|
};
|
|
171
173
|
}
|
|
174
|
+
function clampDuration(val, def) {
|
|
175
|
+
if (val === void 0) return def;
|
|
176
|
+
const n = Number(val);
|
|
177
|
+
if (!Number.isFinite(n) || n < 1e3 || n > 3e5) return def;
|
|
178
|
+
return n;
|
|
179
|
+
}
|
|
180
|
+
function clampInt(val, def, min, max) {
|
|
181
|
+
if (val === void 0) return def;
|
|
182
|
+
const n = Math.round(Number(val));
|
|
183
|
+
if (!Number.isFinite(n) || n < min || n > max) return def;
|
|
184
|
+
return n;
|
|
185
|
+
}
|
|
186
|
+
function sanitizeSelector(sel) {
|
|
187
|
+
if (!sel || typeof sel !== "string") return void 0;
|
|
188
|
+
if (sel.length > 200) return void 0;
|
|
189
|
+
try {
|
|
190
|
+
document.querySelector(sel);
|
|
191
|
+
} catch {
|
|
192
|
+
return void 0;
|
|
193
|
+
}
|
|
194
|
+
return sel;
|
|
195
|
+
}
|
|
172
196
|
function resolveTheme(input) {
|
|
173
197
|
if (!input || input === "auto" || input === "light" || input === "dark") {
|
|
174
198
|
return { ...THEME_DEFAULTS };
|
|
175
199
|
}
|
|
176
|
-
|
|
200
|
+
const allowed = [
|
|
201
|
+
"overlayBg",
|
|
202
|
+
"textColor",
|
|
203
|
+
"textSecondary",
|
|
204
|
+
"accent",
|
|
205
|
+
"accentGlow",
|
|
206
|
+
"hudBg",
|
|
207
|
+
"hudText"
|
|
208
|
+
];
|
|
209
|
+
const filtered = {};
|
|
210
|
+
for (const key of allowed) {
|
|
211
|
+
if (key in input && typeof input[key] === "string") {
|
|
212
|
+
filtered[key] = input[key];
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return { ...THEME_DEFAULTS, ...filtered };
|
|
177
216
|
}
|
|
178
217
|
function resolveNarrative(overrides) {
|
|
179
218
|
if (!overrides) return { ...DEFAULT_SCRIPT };
|
|
@@ -733,26 +772,42 @@ class HiddenEntry {
|
|
|
733
772
|
this._injectShimmerStyles();
|
|
734
773
|
this._createHintContainer();
|
|
735
774
|
const hints = this.script.hiddenEntryHints;
|
|
736
|
-
const FIRST_HINT_DELAY =
|
|
775
|
+
const FIRST_HINT_DELAY = 6e4;
|
|
737
776
|
const HINT_INTERVAL = 6e4;
|
|
738
|
-
const SHIMMER_DELAY =
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
action: () => {
|
|
751
|
-
if (this.targetElement) {
|
|
752
|
-
this.targetElement.classList.add("eeq-entry-target");
|
|
777
|
+
const SHIMMER_DELAY = 12e4;
|
|
778
|
+
const showFirstHint = () => {
|
|
779
|
+
this._stopHintTimer();
|
|
780
|
+
this._showFirstHintWithConfirm(hints[0] ?? "", () => {
|
|
781
|
+
const remaining = hints.slice(1);
|
|
782
|
+
const thresholds = [];
|
|
783
|
+
for (let i = 0; i < remaining.length; i++) {
|
|
784
|
+
thresholds.push({
|
|
785
|
+
at: (i + 1) * HINT_INTERVAL,
|
|
786
|
+
fired: false,
|
|
787
|
+
action: () => this._showHint(remaining[i])
|
|
788
|
+
});
|
|
753
789
|
}
|
|
754
|
-
|
|
755
|
-
|
|
790
|
+
thresholds.push({
|
|
791
|
+
at: SHIMMER_DELAY,
|
|
792
|
+
fired: false,
|
|
793
|
+
action: () => {
|
|
794
|
+
if (this.targetElement) {
|
|
795
|
+
this.targetElement.classList.add("eeq-entry-target");
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
if (thresholds.length === 0) return;
|
|
800
|
+
this._startVisibilityTimer(thresholds);
|
|
801
|
+
});
|
|
802
|
+
};
|
|
803
|
+
const phase1 = [
|
|
804
|
+
{ at: FIRST_HINT_DELAY, fired: false, action: showFirstHint }
|
|
805
|
+
];
|
|
806
|
+
this._startVisibilityTimer(phase1);
|
|
807
|
+
}
|
|
808
|
+
_startVisibilityTimer(thresholds) {
|
|
809
|
+
this._hintVisibleElapsed = 0;
|
|
810
|
+
this._hintVisibleStart = 0;
|
|
756
811
|
const getVisibleElapsed = () => this._hintVisibleElapsed + (this._hintVisibleStart ? Date.now() - this._hintVisibleStart : 0);
|
|
757
812
|
const checkThresholds = () => {
|
|
758
813
|
if (this._destroyed) return;
|
|
@@ -788,6 +843,43 @@ class HiddenEntry {
|
|
|
788
843
|
document.addEventListener("visibilitychange", this._hintVisibilityHandler);
|
|
789
844
|
if (document.visibilityState === "visible") startTimer();
|
|
790
845
|
}
|
|
846
|
+
_showFirstHintWithConfirm(text, onConfirm) {
|
|
847
|
+
if (!this.hintContainer) return;
|
|
848
|
+
const snack = document.createElement("div");
|
|
849
|
+
snack.className = "eeq-snackbar";
|
|
850
|
+
const msg = document.createElement("span");
|
|
851
|
+
msg.textContent = text;
|
|
852
|
+
snack.appendChild(msg);
|
|
853
|
+
const goBtn = document.createElement("button");
|
|
854
|
+
goBtn.className = "eeq-snackbar-btn";
|
|
855
|
+
goBtn.textContent = "Let's go!";
|
|
856
|
+
goBtn.addEventListener("click", () => {
|
|
857
|
+
dismiss();
|
|
858
|
+
onConfirm();
|
|
859
|
+
});
|
|
860
|
+
snack.appendChild(goBtn);
|
|
861
|
+
const noBtn = document.createElement("button");
|
|
862
|
+
noBtn.className = "eeq-snackbar-btn";
|
|
863
|
+
noBtn.textContent = "Not interested";
|
|
864
|
+
noBtn.addEventListener("click", () => {
|
|
865
|
+
try {
|
|
866
|
+
localStorage.setItem("eeq_optout", "1");
|
|
867
|
+
} catch {
|
|
868
|
+
}
|
|
869
|
+
this.cleanup();
|
|
870
|
+
});
|
|
871
|
+
snack.appendChild(noBtn);
|
|
872
|
+
this.hintContainer.appendChild(snack);
|
|
873
|
+
const dismiss = () => {
|
|
874
|
+
snack.style.transform = "translateY(20px)";
|
|
875
|
+
snack.style.opacity = "0";
|
|
876
|
+
setTimeout(() => snack.remove(), 400);
|
|
877
|
+
};
|
|
878
|
+
requestAnimationFrame(() => {
|
|
879
|
+
snack.style.transform = "translateY(0)";
|
|
880
|
+
snack.style.opacity = "1";
|
|
881
|
+
});
|
|
882
|
+
}
|
|
791
883
|
_stopHintTimer() {
|
|
792
884
|
if (this._hintCheckInterval) {
|
|
793
885
|
clearInterval(this._hintCheckInterval);
|
|
@@ -1447,7 +1539,7 @@ class ThreeRenderer {
|
|
|
1447
1539
|
const egg2 = this.eggs[bestIdx];
|
|
1448
1540
|
this._dragRotX = egg2.rotation.x;
|
|
1449
1541
|
this._dragRotY = egg2.rotation.y;
|
|
1450
|
-
|
|
1542
|
+
if (this.canvas) this.canvas.style.cursor = "grabbing";
|
|
1451
1543
|
return;
|
|
1452
1544
|
}
|
|
1453
1545
|
if (this._interactiveEgg === null) return;
|
|
@@ -1460,7 +1552,7 @@ class ThreeRenderer {
|
|
|
1460
1552
|
if (dist > 120) return;
|
|
1461
1553
|
e.preventDefault();
|
|
1462
1554
|
e.stopPropagation();
|
|
1463
|
-
if (this.canvas)
|
|
1555
|
+
if (this.canvas) this.canvas.style.cursor = "grabbing";
|
|
1464
1556
|
this._isDragging = true;
|
|
1465
1557
|
this._dragMoved = false;
|
|
1466
1558
|
this._dragStartX = e.clientX;
|
|
@@ -1510,7 +1602,7 @@ class ThreeRenderer {
|
|
|
1510
1602
|
this._finaleDragTarget = null;
|
|
1511
1603
|
this._cancelLongPress();
|
|
1512
1604
|
if (this._interactiveEgg !== null || this._finaleInteractive) {
|
|
1513
|
-
|
|
1605
|
+
if (this.canvas) this.canvas.style.cursor = "grab";
|
|
1514
1606
|
}
|
|
1515
1607
|
};
|
|
1516
1608
|
this._onWheel = (e) => {
|
|
@@ -1652,7 +1744,7 @@ class ThreeRenderer {
|
|
|
1652
1744
|
/** Make an egg interactively draggable. */
|
|
1653
1745
|
enableInteraction(index) {
|
|
1654
1746
|
this._interactiveEgg = index;
|
|
1655
|
-
|
|
1747
|
+
if (this.canvas) this.canvas.style.cursor = "grab";
|
|
1656
1748
|
}
|
|
1657
1749
|
/** Disable drag interaction. */
|
|
1658
1750
|
disableInteraction() {
|
|
@@ -1661,7 +1753,7 @@ class ThreeRenderer {
|
|
|
1661
1753
|
this._finaleDragTarget = null;
|
|
1662
1754
|
this._finaleInteractive = false;
|
|
1663
1755
|
this._cancelLongPress();
|
|
1664
|
-
|
|
1756
|
+
if (this.canvas) this.canvas.style.cursor = "";
|
|
1665
1757
|
}
|
|
1666
1758
|
/** Trigger spectacular egg reveal. */
|
|
1667
1759
|
revealEgg(index) {
|
|
@@ -1805,7 +1897,7 @@ class ThreeRenderer {
|
|
|
1805
1897
|
this._finaleInteractive = true;
|
|
1806
1898
|
this._finaleDragTarget = null;
|
|
1807
1899
|
this._finalePausedRotation = [false, false, false];
|
|
1808
|
-
|
|
1900
|
+
if (this.canvas) this.canvas.style.cursor = "grab";
|
|
1809
1901
|
for (let i = 0; i < 3; i++) {
|
|
1810
1902
|
const state = this._eggStates[i];
|
|
1811
1903
|
state.phase = "finale";
|
|
@@ -1829,14 +1921,27 @@ class ThreeRenderer {
|
|
|
1829
1921
|
fontFamily: "'Georgia', 'Times New Roman', serif",
|
|
1830
1922
|
textAlign: "center"
|
|
1831
1923
|
});
|
|
1832
|
-
this._greetingOverlay.innerHTML =
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1924
|
+
this._greetingOverlay.innerHTML = "";
|
|
1925
|
+
const headingDiv = document.createElement("div");
|
|
1926
|
+
Object.assign(headingDiv.style, {
|
|
1927
|
+
fontSize: "48px",
|
|
1928
|
+
color: "#fff8e8",
|
|
1929
|
+
textShadow: "0 0 60px rgba(212,165,80,0.7), 0 0 20px rgba(212,165,80,0.4), 0 2px 8px rgba(0,0,0,0.6)",
|
|
1930
|
+
marginBottom: "10px",
|
|
1931
|
+
letterSpacing: "0.03em",
|
|
1932
|
+
fontWeight: "bold"
|
|
1933
|
+
});
|
|
1934
|
+
headingDiv.textContent = "Happy Easter! ๐ฐ๐ฅ";
|
|
1935
|
+
this._greetingOverlay.appendChild(headingDiv);
|
|
1936
|
+
const subDiv = document.createElement("div");
|
|
1937
|
+
Object.assign(subDiv.style, {
|
|
1938
|
+
fontSize: "17px",
|
|
1939
|
+
color: "rgba(245,240,230,0.85)",
|
|
1940
|
+
fontStyle: "italic",
|
|
1941
|
+
textShadow: "0 0 12px rgba(212,165,80,0.3), 0 1px 6px rgba(0,0,0,0.4)"
|
|
1942
|
+
});
|
|
1943
|
+
subDiv.textContent = "Wishing you joy, peace, and light";
|
|
1944
|
+
this._greetingOverlay.appendChild(subDiv);
|
|
1840
1945
|
document.body.appendChild(this._greetingOverlay);
|
|
1841
1946
|
requestAnimationFrame(() => {
|
|
1842
1947
|
requestAnimationFrame(() => {
|
|
@@ -3273,7 +3378,7 @@ const _ResultsRenderer = class _ResultsRenderer {
|
|
|
3273
3378
|
this.shadow.appendChild(style);
|
|
3274
3379
|
const panel = document.createElement("div");
|
|
3275
3380
|
panel.className = "eeq-results";
|
|
3276
|
-
|
|
3381
|
+
this._buildContentDOM(panel, score);
|
|
3277
3382
|
this.shadow.appendChild(panel);
|
|
3278
3383
|
requestAnimationFrame(() => {
|
|
3279
3384
|
requestAnimationFrame(() => {
|
|
@@ -3293,7 +3398,7 @@ const _ResultsRenderer = class _ResultsRenderer {
|
|
|
3293
3398
|
this.shadow = null;
|
|
3294
3399
|
}
|
|
3295
3400
|
// โโโ Content โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
3296
|
-
|
|
3401
|
+
_buildContentDOM(parent, s) {
|
|
3297
3402
|
const bp = s.behaviorProfile;
|
|
3298
3403
|
const actionIcons = {
|
|
3299
3404
|
clicker: "๐ฑ",
|
|
@@ -3314,31 +3419,56 @@ const _ResultsRenderer = class _ResultsRenderer {
|
|
|
3314
3419
|
explorer: "๐งญ",
|
|
3315
3420
|
philosopher: "๐"
|
|
3316
3421
|
};
|
|
3317
|
-
const
|
|
3318
|
-
|
|
3319
|
-
const
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3422
|
+
const inner = document.createElement("div");
|
|
3423
|
+
inner.className = "eeq-results-inner";
|
|
3424
|
+
const title = document.createElement("div");
|
|
3425
|
+
title.className = "eeq-results-title";
|
|
3426
|
+
title.textContent = `ยซ ${bp.title} ยป`;
|
|
3427
|
+
inner.appendChild(title);
|
|
3428
|
+
const time = document.createElement("div");
|
|
3429
|
+
time.className = "eeq-time";
|
|
3430
|
+
time.textContent = formatTime(s.totalTime);
|
|
3431
|
+
inner.appendChild(time);
|
|
3432
|
+
const badgesDiv = document.createElement("div");
|
|
3433
|
+
badgesDiv.className = "eeq-badges";
|
|
3434
|
+
const icons = [
|
|
3435
|
+
{ icon: actionIcons[bp.dominantAction], label: bp.dominantAction },
|
|
3436
|
+
{ icon: mouseIcons[bp.mousePersonality], label: bp.mousePersonality },
|
|
3437
|
+
{ icon: paceIcons[bp.pace], label: bp.pace }
|
|
3438
|
+
];
|
|
3439
|
+
for (const { icon, label } of icons) {
|
|
3440
|
+
if (!icon) continue;
|
|
3441
|
+
const span = document.createElement("span");
|
|
3442
|
+
span.className = "eeq-badge";
|
|
3443
|
+
span.title = label;
|
|
3444
|
+
span.textContent = icon;
|
|
3445
|
+
badgesDiv.appendChild(span);
|
|
3446
|
+
}
|
|
3447
|
+
inner.appendChild(badgesDiv);
|
|
3448
|
+
const invite = document.createElement("div");
|
|
3449
|
+
invite.className = "eeq-share-invite";
|
|
3450
|
+
invite.textContent = "share your result with friends ๐ฅ";
|
|
3451
|
+
inner.appendChild(invite);
|
|
3452
|
+
const actions = document.createElement("div");
|
|
3453
|
+
actions.className = "eeq-results-actions";
|
|
3454
|
+
const shareBtn = document.createElement("button");
|
|
3455
|
+
shareBtn.className = "eeq-btn eeq-btn-share";
|
|
3456
|
+
shareBtn.title = "share result";
|
|
3457
|
+
shareBtn.innerHTML = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4.5 10.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm7-4a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm0 8a2 2 0 1 1 0-4 2 2 0 0 1 0 4z" stroke="currentColor" stroke-width="1.2"/><path d="M6.3 9.2l3.4 1.6M6.3 7.8l3.4-1.6" stroke="currentColor" stroke-width="1.2"/></svg>';
|
|
3458
|
+
const shareLabel = document.createElement("span");
|
|
3459
|
+
shareLabel.textContent = "share";
|
|
3460
|
+
shareBtn.appendChild(shareLabel);
|
|
3461
|
+
actions.appendChild(shareBtn);
|
|
3462
|
+
const finishBtn = document.createElement("button");
|
|
3463
|
+
finishBtn.className = "eeq-btn eeq-btn-finish";
|
|
3464
|
+
finishBtn.title = "finish";
|
|
3465
|
+
finishBtn.innerHTML = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 8.5l3 3 5-6.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
3466
|
+
const finishLabel = document.createElement("span");
|
|
3467
|
+
finishLabel.textContent = "finish";
|
|
3468
|
+
finishBtn.appendChild(finishLabel);
|
|
3469
|
+
actions.appendChild(finishBtn);
|
|
3470
|
+
inner.appendChild(actions);
|
|
3471
|
+
parent.appendChild(inner);
|
|
3342
3472
|
}
|
|
3343
3473
|
// โโโ 2D Egg Drawing (type-accurate) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
3344
3474
|
_makeRand(seed) {
|
|
@@ -3703,9 +3833,6 @@ const _ResultsRenderer = class _ResultsRenderer {
|
|
|
3703
3833
|
span.textContent = orig;
|
|
3704
3834
|
}, 1500);
|
|
3705
3835
|
}
|
|
3706
|
-
_escapeHtml(s) {
|
|
3707
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
3708
|
-
}
|
|
3709
3836
|
// โโโ Styles โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
3710
3837
|
_getStyles() {
|
|
3711
3838
|
const t = this.config.theme;
|
|
@@ -4092,7 +4219,11 @@ class Persistence {
|
|
|
4092
4219
|
try {
|
|
4093
4220
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
4094
4221
|
if (!raw) return [];
|
|
4095
|
-
|
|
4222
|
+
const parsed = JSON.parse(raw);
|
|
4223
|
+
if (!Array.isArray(parsed)) return [];
|
|
4224
|
+
return parsed.filter(
|
|
4225
|
+
(item) => typeof item === "object" && item !== null && typeof item.totalTime === "number" && Number.isFinite(item.totalTime)
|
|
4226
|
+
);
|
|
4096
4227
|
} catch {
|
|
4097
4228
|
return [];
|
|
4098
4229
|
}
|