easter-egg-quest 1.0.19 → 1.0.20

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.
@@ -65,10 +65,11 @@ const DEFAULT_SCRIPT = {
65
65
  "Every living thing knows it. You’ve been doing it your whole life without thinking."
66
66
  ],
67
67
  stage3Reactions: [
68
- "move for a few seconds",
69
- "then hold still for a moment",
70
- "don’t rush it",
71
- "alternate move and pause",
68
+ "one truth alone is not enough",
69
+ "the other alone is not enough either",
70
+ "what do all living things share?",
71
+ "you have known it since the beginning",
72
+ "listen to yourself",
72
73
  "in",
73
74
  "out"
74
75
  ],
@@ -1764,6 +1765,7 @@ class ThreeRenderer {
1764
1765
  this._greetingOverlay = null;
1765
1766
  this._trailParticles = [];
1766
1767
  this._ambientParticles = [];
1768
+ this._lastAmbientSpawnAt = 0;
1767
1769
  this._revealParticles = [];
1768
1770
  this._disposed = false;
1769
1771
  this._interactiveEgg = null;
@@ -2130,32 +2132,43 @@ class ThreeRenderer {
2130
2132
  }
2131
2133
  }
2132
2134
  }
2133
- /** Spawn gentle ambient particles to show stage progress. */
2134
- showProgressParticles(progress) {
2135
+ /** Spawn ambient particles to show stage progress. */
2136
+ showProgressParticles(progress, source = "default") {
2135
2137
  if (!this.THREE || !this.scene || progress < 0.05) return;
2136
2138
  const T = this.THREE;
2137
- if (Math.random() > progress * 0.3) return;
2138
- const angle = Math.random() * Math.PI * 2;
2139
- const radius = 2 + Math.random() * 2;
2140
- const x = Math.cos(angle) * radius;
2141
- const y = -2 + Math.random() * 4;
2142
- const size = 0.02 + Math.random() * 0.025;
2143
- const geo = this._createMiniEggGeo(T, size);
2144
- const mat = this._createMiniEggMat(T, 0);
2145
- const p = new T.Mesh(geo, mat);
2146
- p.position.set(x, y, -1 + Math.random() * 0.5);
2147
- p.rotation.set(
2148
- Math.random() * Math.PI,
2149
- Math.random() * Math.PI,
2150
- Math.random() * Math.PI
2151
- );
2152
- this.scene.add(p);
2153
- this._ambientParticles.push({
2154
- mesh: p,
2155
- life: 1,
2156
- vy: 0.2 + Math.random() * 0.3,
2157
- fadeIn: true
2158
- });
2139
+ const now = performance.now();
2140
+ const isRhythm = source === "rhythm";
2141
+ if (isRhythm) {
2142
+ const minGap = Math.max(80, 180 - progress * 120);
2143
+ if (now - this._lastAmbientSpawnAt < minGap) return;
2144
+ } else if (Math.random() > progress * 0.3) {
2145
+ return;
2146
+ }
2147
+ this._lastAmbientSpawnAt = now;
2148
+ const spawnCount = isRhythm && progress > 0.6 ? 2 : 1;
2149
+ for (let i = 0; i < spawnCount; i++) {
2150
+ const angle = Math.random() * Math.PI * 2;
2151
+ const radius = isRhythm ? 1.1 + Math.random() * 1.8 : 2 + Math.random() * 2;
2152
+ const x = Math.cos(angle) * radius;
2153
+ const y = isRhythm ? -2.8 - Math.random() * 0.9 : -2 + Math.random() * 4;
2154
+ const size = isRhythm ? 0.03 + Math.random() * 0.03 : 0.02 + Math.random() * 0.025;
2155
+ const geo = this._createMiniEggGeo(T, size);
2156
+ const mat = this._createMiniEggMat(T, 0);
2157
+ const p = new T.Mesh(geo, mat);
2158
+ p.position.set(x, y, -1 + Math.random() * 0.5);
2159
+ p.rotation.set(
2160
+ Math.random() * Math.PI,
2161
+ Math.random() * Math.PI,
2162
+ Math.random() * Math.PI
2163
+ );
2164
+ this.scene.add(p);
2165
+ this._ambientParticles.push({
2166
+ mesh: p,
2167
+ life: isRhythm ? 1.25 : 1,
2168
+ vy: isRhythm ? 0.45 + Math.random() * 0.35 : 0.2 + Math.random() * 0.3,
2169
+ fadeIn: true
2170
+ });
2171
+ }
2159
2172
  if (this._ambientParticles.length > 60) {
2160
2173
  const old = this._ambientParticles.shift();
2161
2174
  if (old) {
@@ -4778,10 +4791,10 @@ class RhythmStage {
4778
4791
  this._lastPhaseCount = 0;
4779
4792
  this._bestAccuracy = 0;
4780
4793
  this._lastGuideTime = 0;
4781
- this.IDEAL_MOVE_MIN = 1800;
4782
- this.IDEAL_MOVE_MAX = 5e3;
4783
- this.IDEAL_PAUSE_MIN = 1200;
4784
- this.IDEAL_PAUSE_MAX = 4e3;
4794
+ this.IDEAL_MOVE_MIN = 900;
4795
+ this.IDEAL_MOVE_MAX = 4200;
4796
+ this.IDEAL_PAUSE_MIN = 600;
4797
+ this.IDEAL_PAUSE_MAX = 2800;
4785
4798
  this.config = config;
4786
4799
  this.script = script;
4787
4800
  this.input = input;
@@ -4792,7 +4805,7 @@ class RhythmStage {
4792
4805
  this._attempts = 1;
4793
4806
  this._goodCycles = 0;
4794
4807
  this._totalCycles = 0;
4795
- this.input.configurePhaseDetection({ stillThresholdMs: 900, minPhaseMs: 500 });
4808
+ this.input.configurePhaseDetection({ stillThresholdMs: 450, minPhaseMs: 350 });
4796
4809
  this.input.resetPhases();
4797
4810
  this.input.resetCounts();
4798
4811
  this.bus.emit("narrative:clear");
@@ -4812,7 +4825,6 @@ class RhythmStage {
4812
4825
  this.input.resetPhases();
4813
4826
  this._lastPhaseCount = this.input.phases.length;
4814
4827
  this._introPlayed = true;
4815
- this.bus.emit("narrative:show", "move for a few seconds, then hold still");
4816
4828
  this._lastGuideTime = Date.now();
4817
4829
  }
4818
4830
  update(_dt) {
@@ -4828,7 +4840,7 @@ class RhythmStage {
4828
4840
  if (isGood) {
4829
4841
  this._goodCycles++;
4830
4842
  } else {
4831
- this._goodCycles = Math.max(0, this._goodCycles - 1);
4843
+ this._goodCycles = Math.max(0, this._goodCycles - 0.5);
4832
4844
  this._showReaction();
4833
4845
  }
4834
4846
  this._lastPhaseCount += 2;
@@ -4849,7 +4861,7 @@ class RhythmStage {
4849
4861
  });
4850
4862
  if (accuracy === 0 && Date.now() - this._lastGuideTime > 12e3) {
4851
4863
  this._lastGuideTime = Date.now();
4852
- this.bus.emit("narrative:show", "try this: move 2-4s, then stay still 1-3s");
4864
+ this._showReaction();
4853
4865
  }
4854
4866
  if (this._goodCycles >= requiredCycles) {
4855
4867
  this._status = "complete";
@@ -5017,7 +5029,7 @@ class PageBreather {
5017
5029
  this._overlay.style.opacity = String(Math.min(0.9, opacity));
5018
5030
  this._overlay.style.transform = `scale(${1 + wave * 0.015})`;
5019
5031
  if (this._label) {
5020
- this._label.textContent = shouldMove ? "Move" : "Hold still";
5032
+ this._label.textContent = shouldMove ? "In" : "Out";
5021
5033
  this._label.style.opacity = shouldMove === this._isUserMoving ? "0.98" : "0.82";
5022
5034
  this._label.style.boxShadow = this._inSync ? "0 0 28px rgba(212,165,80,0.4)" : "0 0 20px rgba(255,255,255,0.08)";
5023
5035
  this._label.style.borderColor = this._inSync ? "rgba(212,165,80,0.55)" : "rgba(255,255,255,0.12)";
@@ -5063,7 +5075,7 @@ class PageBreather {
5063
5075
  "box-shadow:0 0 20px rgba(255,255,255,0.08)",
5064
5076
  "opacity:0.78"
5065
5077
  ].join(";");
5066
- label.textContent = "Move";
5078
+ label.textContent = "In";
5067
5079
  document.body.appendChild(label);
5068
5080
  this._label = label;
5069
5081
  this._tick();
@@ -5194,9 +5206,10 @@ class GameController {
5194
5206
  (_a3 = this.eggRenderer) == null ? void 0 : _a3.setBreathIntensity(data.accuracy);
5195
5207
  (_b3 = this.pageBreather) == null ? void 0 : _b3.update(data.accuracy, data.isMoving);
5196
5208
  const rhythmSignal = Math.max(data.accuracy, data.progress * 0.75);
5197
- const hasLiveCycleSignal = data.moveDuration > 1200 || data.stillDuration > 900;
5209
+ const hasLiveCycleSignal = data.moveDuration > 700 || data.stillDuration > 700;
5198
5210
  if ((rhythmSignal > 0.08 || hasLiveCycleSignal) && this.threeRenderer) {
5199
- this.threeRenderer.showProgressParticles(0.45 + rhythmSignal * 0.55);
5211
+ const liveSignal = hasLiveCycleSignal ? 0.2 : 0;
5212
+ this.threeRenderer.showProgressParticles(Math.max(0.35, 0.45 + Math.max(rhythmSignal, liveSignal) * 0.55), "rhythm");
5200
5213
  } else if (this.threeRenderer) {
5201
5214
  this.threeRenderer.fadeOutAmbientParticles();
5202
5215
  }