easter-egg-quest 1.0.22 → 1.0.24

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.
@@ -2178,6 +2178,41 @@ class ThreeRenderer {
2178
2178
  }
2179
2179
  }
2180
2180
  }
2181
+ burstRhythmParticles(progress, cycles) {
2182
+ if (!this.THREE || !this.scene) return;
2183
+ const T = this.THREE;
2184
+ const burstSize = Math.min(14, 6 + Math.floor(progress * 6) + Math.min(3, Math.floor(cycles)));
2185
+ for (let i = 0; i < burstSize; i++) {
2186
+ const angle = Math.PI * 2 * i / burstSize + (Math.random() - 0.5) * 0.35;
2187
+ const radius = 0.45 + Math.random() * 2.15;
2188
+ const x = Math.cos(angle) * radius;
2189
+ const y = -2.95 - Math.random() * 0.75;
2190
+ const size = 0.036 + Math.random() * 0.038;
2191
+ const geo = this._createMiniEggGeo(T, size);
2192
+ const mat = this._createMiniEggMat(T, 0.18 + Math.random() * 0.12);
2193
+ const particle = new T.Mesh(geo, mat);
2194
+ particle.position.set(x, y, -1 + Math.random() * 0.8);
2195
+ particle.rotation.set(
2196
+ Math.random() * Math.PI,
2197
+ Math.random() * Math.PI,
2198
+ Math.random() * Math.PI
2199
+ );
2200
+ this.scene.add(particle);
2201
+ this._ambientParticles.push({
2202
+ mesh: particle,
2203
+ life: 1.7 + Math.random() * 0.45,
2204
+ vy: 0.85 + Math.random() * 0.65,
2205
+ fadeIn: true
2206
+ });
2207
+ }
2208
+ while (this._ambientParticles.length > 120) {
2209
+ const old = this._ambientParticles.shift();
2210
+ if (!old) break;
2211
+ this.scene.remove(old.mesh);
2212
+ old.mesh.geometry.dispose();
2213
+ old.mesh.material.dispose();
2214
+ }
2215
+ }
2181
2216
  /** Mark all ambient particles for rapid fade-out (rhythm lost). */
2182
2217
  fadeOutAmbientParticles() {
2183
2218
  for (const p of this._ambientParticles) {
@@ -3681,9 +3716,11 @@ const _ResultsRenderer = class _ResultsRenderer {
3681
3716
  panel.classList.add("eeq-results-visible");
3682
3717
  });
3683
3718
  });
3684
- (_a2 = this.shadow.querySelector(".eeq-btn-finish")) == null ? void 0 : _a2.addEventListener("click", () => {
3719
+ (_a2 = this.shadow.querySelector(".eeq-btn-finish")) == null ? void 0 : _a2.addEventListener("click", (event) => {
3685
3720
  var _a3;
3686
- return (_a3 = this._onFinish) == null ? void 0 : _a3.call(this);
3721
+ event.preventDefault();
3722
+ event.stopPropagation();
3723
+ (_a3 = this._onFinish) == null ? void 0 : _a3.call(this);
3687
3724
  });
3688
3725
  (_b2 = this.shadow.querySelector(".eeq-btn-share")) == null ? void 0 : _b2.addEventListener("click", () => this._copyShareImage(score));
3689
3726
  }
@@ -4500,6 +4537,7 @@ class ScoringEngine {
4500
4537
  }
4501
4538
  const STORAGE_KEY = "eeq_scores";
4502
4539
  const PROGRESS_KEY = "eeq_progress";
4540
+ const COMPLETION_KEY = "eeq_completed";
4503
4541
  class Persistence {
4504
4542
  constructor(enabled) {
4505
4543
  this._enabled = enabled;
@@ -4572,6 +4610,22 @@ class Persistence {
4572
4610
  } catch {
4573
4611
  }
4574
4612
  }
4613
+ markCompleted() {
4614
+ if (!this._enabled) return;
4615
+ try {
4616
+ localStorage.setItem(COMPLETION_KEY, "1");
4617
+ localStorage.removeItem(PROGRESS_KEY);
4618
+ } catch {
4619
+ }
4620
+ }
4621
+ isCompleted() {
4622
+ if (!this._enabled) return false;
4623
+ try {
4624
+ return localStorage.getItem(COMPLETION_KEY) === "1";
4625
+ } catch {
4626
+ return false;
4627
+ }
4628
+ }
4575
4629
  }
4576
4630
  class StillnessStage {
4577
4631
  constructor(config, script, input, bus) {
@@ -4841,6 +4895,10 @@ class RhythmStage {
4841
4895
  if (isGood) {
4842
4896
  this._goodCycles++;
4843
4897
  this._lastGoodCycleAt = Date.now();
4898
+ this.bus.emit("rhythm:cycle", {
4899
+ progress: Math.min(1, this._goodCycles / requiredCycles),
4900
+ cycles: this._goodCycles
4901
+ });
4844
4902
  } else {
4845
4903
  this._goodCycles = Math.max(0, this._goodCycles - 0.5);
4846
4904
  this._showReaction();
@@ -5038,7 +5096,6 @@ class PageBreather {
5038
5096
  this._targetIntensity = 0;
5039
5097
  this._rafId = 0;
5040
5098
  this._overlay = null;
5041
- this._label = null;
5042
5099
  this._startTime = 0;
5043
5100
  this._isUserMoving = false;
5044
5101
  this._inSync = false;
@@ -5059,12 +5116,6 @@ class PageBreather {
5059
5116
  const opacity = this._intensity * (baseOpacity + syncBonus);
5060
5117
  this._overlay.style.opacity = String(Math.min(0.9, opacity));
5061
5118
  this._overlay.style.transform = `scale(${1 + wave * (shouldMove ? 0.01 : 0.02)})`;
5062
- if (this._label) {
5063
- this._label.textContent = shouldMove ? "In" : "Out";
5064
- this._label.style.opacity = this._phaseMatch ? "0.98" : "0.78";
5065
- this._label.style.boxShadow = this._inSync ? "0 0 28px rgba(212,165,80,0.4)" : "0 0 20px rgba(255,255,255,0.08)";
5066
- this._label.style.borderColor = this._inSync ? "rgba(212,165,80,0.55)" : "rgba(255,255,255,0.12)";
5067
- }
5068
5119
  };
5069
5120
  }
5070
5121
  start() {
@@ -5086,29 +5137,6 @@ class PageBreather {
5086
5137
  ].join(";");
5087
5138
  document.body.appendChild(el);
5088
5139
  this._overlay = el;
5089
- const label = document.createElement("div");
5090
- label.style.cssText = [
5091
- "position:fixed",
5092
- "left:50%",
5093
- "top:18%",
5094
- "transform:translateX(-50%)",
5095
- "pointer-events:none",
5096
- "z-index:999981",
5097
- "padding:8px 14px",
5098
- "border-radius:999px",
5099
- "font-family:Georgia, Times New Roman, serif",
5100
- "font-size:12px",
5101
- "letter-spacing:0.12em",
5102
- "text-transform:uppercase",
5103
- "color:rgba(255,248,232,0.95)",
5104
- "background:rgba(8,10,18,0.36)",
5105
- "border:1px solid rgba(255,255,255,0.12)",
5106
- "box-shadow:0 0 20px rgba(255,255,255,0.08)",
5107
- "opacity:0.78"
5108
- ].join(";");
5109
- label.textContent = "In";
5110
- document.body.appendChild(label);
5111
- this._label = label;
5112
5140
  this._tick();
5113
5141
  }
5114
5142
  update(accuracy, isMoving, targetPhase, phaseMatch, signal) {
@@ -5126,14 +5154,12 @@ class PageBreather {
5126
5154
  return this._inSync;
5127
5155
  }
5128
5156
  stop() {
5129
- var _a2, _b2;
5157
+ var _a2;
5130
5158
  if (!this._active) return;
5131
5159
  this._active = false;
5132
5160
  cancelAnimationFrame(this._rafId);
5133
5161
  (_a2 = this._overlay) == null ? void 0 : _a2.remove();
5134
5162
  this._overlay = null;
5135
- (_b2 = this._label) == null ? void 0 : _b2.remove();
5136
- this._label = null;
5137
5163
  this._intensity = 0;
5138
5164
  this._targetIntensity = 0;
5139
5165
  this._inSync = false;
@@ -5218,6 +5244,10 @@ class GameController {
5218
5244
  // ─── Lifecycle ─────────────────────────────────────────────────────────
5219
5245
  async init() {
5220
5246
  var _a2, _b2;
5247
+ if (this.persistence.isCompleted()) {
5248
+ this._destroyed = true;
5249
+ return;
5250
+ }
5221
5251
  this.fsm.onTransition((from, to) => this._onTransition(from, to));
5222
5252
  this.bus.on("narrative:show", (text) => {
5223
5253
  var _a3;
@@ -5238,6 +5268,10 @@ class GameController {
5238
5268
  var _a3;
5239
5269
  (_a3 = this.eggRenderer) == null ? void 0 : _a3.addTrail(data.x, data.y, data.velocity);
5240
5270
  });
5271
+ this.bus.on("rhythm:cycle", (data) => {
5272
+ if (!this.threeRenderer) return;
5273
+ this.threeRenderer.burstRhythmParticles(data.progress, data.cycles);
5274
+ });
5241
5275
  this.bus.on("rhythm:breathe", (data) => {
5242
5276
  var _a3, _b3;
5243
5277
  (_a3 = this.eggRenderer) == null ? void 0 : _a3.setBreathIntensity(data.accuracy);
@@ -5248,9 +5282,7 @@ class GameController {
5248
5282
  data.phaseMatch,
5249
5283
  Math.max(data.liveConfidence * 0.55, data.cycleSignal)
5250
5284
  );
5251
- if (data.cycleSignal > 0.12 && this.threeRenderer) {
5252
- this.threeRenderer.showProgressParticles(0.35 + Math.max(data.progress, data.cycleSignal) * 0.65, "rhythm");
5253
- } else if (this.threeRenderer) {
5285
+ if (data.cycleSignal <= 0.12 && this.threeRenderer) {
5254
5286
  this.threeRenderer.fadeOutAmbientParticles();
5255
5287
  }
5256
5288
  });
@@ -5432,6 +5464,7 @@ class GameController {
5432
5464
  // ─── Entry ─────────────────────────────────────────────────────────────
5433
5465
  async _startEntry() {
5434
5466
  var _a2;
5467
+ if (this.persistence.isCompleted()) return;
5435
5468
  try {
5436
5469
  if (localStorage.getItem("eeq_optout") === "1") return;
5437
5470
  } catch {
@@ -5681,7 +5714,9 @@ class GameController {
5681
5714
  this.results.show(
5682
5715
  score,
5683
5716
  () => {
5717
+ this.persistence.markCompleted();
5684
5718
  this.destroy();
5719
+ this._reloadPage();
5685
5720
  }
5686
5721
  );
5687
5722
  (_c = (_b2 = this.config.callbacks).onComplete) == null ? void 0 : _c.call(_b2, score);
@@ -5729,6 +5764,17 @@ class GameController {
5729
5764
  _wait(ms) {
5730
5765
  return new Promise((r) => setTimeout(r, ms));
5731
5766
  }
5767
+ _reloadPage() {
5768
+ try {
5769
+ window.location.reload();
5770
+ return;
5771
+ } catch {
5772
+ }
5773
+ try {
5774
+ window.location.assign(window.location.href);
5775
+ } catch {
5776
+ }
5777
+ }
5732
5778
  }
5733
5779
  let _instance = null;
5734
5780
  const EasterEggQuest = {