easter-egg-quest 1.0.1 โ 1.0.3
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.
- package/README.md +45 -51
- package/dist/easter-egg-quest.es.js +14 -14
- package/dist/easter-egg-quest.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
# ๐ฅ Easter Egg Quest
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Something is hiding on your website. Your visitors don't know it yet.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
One line of code โ and your page holds a secret. A poetic journey disguised as ordinary text. Three riddles. Three eggs. One question: *will they notice?*
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
No buttons. No banners. No hints. Just a quiet invitation woven into the fabric of your page.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Those who find it will never look at your website the same way again.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
### One line (CDN)
|
|
10
16
|
|
|
11
17
|
```html
|
|
12
|
-
<script src="https://unpkg.com/easter-egg-quest"></script>
|
|
13
|
-
<script>
|
|
14
|
-
EasterEggQuest.init();
|
|
15
|
-
</script>
|
|
18
|
+
<script src="https://unpkg.com/easter-egg-quest/dist/easter-egg-quest.umd.js"></script>
|
|
16
19
|
```
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
Nothing else needed. The script activates itself after your page loads.
|
|
19
22
|
|
|
20
|
-
### npm
|
|
23
|
+
### npm / yarn
|
|
21
24
|
|
|
22
25
|
```bash
|
|
23
26
|
npm install easter-egg-quest
|
|
@@ -29,59 +32,50 @@ import { EasterEggQuest } from 'easter-egg-quest';
|
|
|
29
32
|
EasterEggQuest.init();
|
|
30
33
|
```
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## What happens next?
|
|
38
|
+
|
|
39
|
+
That's for your visitors to discover.
|
|
40
|
+
|
|
41
|
+
We'll only say this: the experience has three chapters, each asking something different. Something about stillness. Something about motion. Something about the space between.
|
|
33
42
|
|
|
34
|
-
|
|
35
|
-
2. **Stage 1: Stillness** โ stop moving. The egg comes to those who wait
|
|
36
|
-
3. **Stage 2: Motion** โ keep moving. Be the river
|
|
37
|
-
4. **Stage 3: Rhythm** โ find the pulse. Breathe
|
|
38
|
-
5. **Finale** โ all three eggs appear in a 3D carousel with a "Happy Easter!" greeting
|
|
39
|
-
6. **Results** โ a personalized profile card based on your behavior (shareable as image)
|
|
43
|
+
The whole thing takes a few minutes. At the end, each person gets a unique result โ a portrait of how they moved through the unknown.
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
---
|
|
42
46
|
|
|
43
47
|
## Configuration
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
Everything works out of the box. But if you want control:
|
|
46
50
|
|
|
47
51
|
```js
|
|
48
52
|
EasterEggQuest.init({
|
|
49
|
-
// Lifecycle callbacks
|
|
50
53
|
callbacks: {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
onEggFound: (eggIndex) => {},
|
|
55
|
-
onComplete: (score) => {},
|
|
56
|
-
onDestroy: () => {},
|
|
54
|
+
onComplete: (score) => {
|
|
55
|
+
// The visitor finished the quest
|
|
56
|
+
},
|
|
57
57
|
},
|
|
58
58
|
|
|
59
|
-
// Stage durations
|
|
60
59
|
stageDurations: {
|
|
61
60
|
stillnessMs: 20000,
|
|
62
61
|
motionMs: 20000,
|
|
63
62
|
rhythmCycles: 6,
|
|
64
63
|
},
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
renderer: 'auto',
|
|
65
|
+
renderer: 'auto', // 'auto' | '3d' | '2d'
|
|
68
66
|
|
|
69
|
-
// Accessibility
|
|
70
67
|
accessibility: {
|
|
71
|
-
reducedMotion: 'auto',
|
|
72
|
-
disableHiddenEntry: false,
|
|
68
|
+
reducedMotion: 'auto',
|
|
69
|
+
disableHiddenEntry: false,
|
|
73
70
|
},
|
|
74
71
|
|
|
75
|
-
// Hidden entry targeting
|
|
76
72
|
hiddenEntry: {
|
|
77
|
-
selector: undefined,
|
|
78
|
-
excludeSelectors: [],
|
|
73
|
+
selector: undefined,
|
|
74
|
+
excludeSelectors: [],
|
|
79
75
|
},
|
|
80
76
|
|
|
81
|
-
// Custom narrative text
|
|
82
77
|
narrative: {
|
|
83
|
-
//
|
|
84
|
-
// stage1Intro: ['your', 'custom', 'lines'],
|
|
78
|
+
// Your own words for any chapter
|
|
85
79
|
},
|
|
86
80
|
});
|
|
87
81
|
```
|
|
@@ -89,26 +83,26 @@ EasterEggQuest.init({
|
|
|
89
83
|
## API
|
|
90
84
|
|
|
91
85
|
```js
|
|
92
|
-
EasterEggQuest.init(config?) //
|
|
93
|
-
EasterEggQuest.pause() //
|
|
94
|
-
EasterEggQuest.resume() //
|
|
95
|
-
EasterEggQuest.destroy() //
|
|
86
|
+
EasterEggQuest.init(config?) // Awaken the quest
|
|
87
|
+
EasterEggQuest.pause() // Freeze time
|
|
88
|
+
EasterEggQuest.resume() // Let it breathe again
|
|
89
|
+
EasterEggQuest.destroy() // Erase all traces
|
|
96
90
|
```
|
|
97
91
|
|
|
98
|
-
|
|
92
|
+
---
|
|
99
93
|
|
|
100
|
-
|
|
94
|
+
## Safe by design
|
|
101
95
|
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
96
|
+
- Your layout stays untouched โ everything floats above
|
|
97
|
+
- Styles are sealed in Shadow DOM โ no collisions
|
|
98
|
+
- Dangerous buttons (Buy, Delete, Submit) are never used as entry points
|
|
99
|
+
- `destroy()` leaves your page exactly as it was
|
|
106
100
|
|
|
107
|
-
##
|
|
101
|
+
## Compatibility
|
|
108
102
|
|
|
109
|
-
Chrome
|
|
103
|
+
Chrome ยท Edge ยท Firefox ยท Safari ยท Mobile
|
|
110
104
|
|
|
111
|
-
Falls back
|
|
105
|
+
Falls back gracefully without WebGL.
|
|
112
106
|
|
|
113
107
|
## License
|
|
114
108
|
|
|
@@ -729,8 +729,8 @@ class HiddenEntry {
|
|
|
729
729
|
this._injectShimmerStyles();
|
|
730
730
|
this._createHintContainer();
|
|
731
731
|
const hints = this.script.hiddenEntryHints;
|
|
732
|
-
const FIRST_HINT_DELAY =
|
|
733
|
-
const HINT_INTERVAL =
|
|
732
|
+
const FIRST_HINT_DELAY = 3e5;
|
|
733
|
+
const HINT_INTERVAL = 6e4;
|
|
734
734
|
for (let i = 0; i < hints.length; i++) {
|
|
735
735
|
const delay = FIRST_HINT_DELAY + i * HINT_INTERVAL;
|
|
736
736
|
const timer = setTimeout(() => {
|
|
@@ -739,7 +739,7 @@ class HiddenEntry {
|
|
|
739
739
|
}, delay);
|
|
740
740
|
this.hintTimers.push(timer);
|
|
741
741
|
}
|
|
742
|
-
const shimmerDelay =
|
|
742
|
+
const shimmerDelay = 42e4;
|
|
743
743
|
const shimmerTimer = setTimeout(() => {
|
|
744
744
|
if (this._destroyed || !this.targetElement) return;
|
|
745
745
|
this.targetElement.classList.add("eeq-entry-target");
|
|
@@ -950,10 +950,10 @@ class NarrativeRenderer {
|
|
|
950
950
|
this.currentLine = line;
|
|
951
951
|
this.clearTimer = setTimeout(() => {
|
|
952
952
|
this.clear();
|
|
953
|
-
},
|
|
953
|
+
}, 12e3);
|
|
954
954
|
}
|
|
955
955
|
/** Show a sequence of lines with pauses. */
|
|
956
|
-
async showSequence(lines, pauseMs =
|
|
956
|
+
async showSequence(lines, pauseMs = 4500) {
|
|
957
957
|
for (const line of lines) {
|
|
958
958
|
this.showLine(line);
|
|
959
959
|
await new Promise((r) => setTimeout(r, pauseMs));
|
|
@@ -3980,7 +3980,7 @@ class StillnessStage {
|
|
|
3980
3980
|
const introLines = this.script.stage1Intro;
|
|
3981
3981
|
for (let i = 0; i < introLines.length; i++) {
|
|
3982
3982
|
this.bus.emit("narrative:show", introLines[i]);
|
|
3983
|
-
await this._wait(
|
|
3983
|
+
await this._wait(4500);
|
|
3984
3984
|
}
|
|
3985
3985
|
this.bus.emit("narrative:clear");
|
|
3986
3986
|
await this._wait(1e3);
|
|
@@ -4020,7 +4020,7 @@ class StillnessStage {
|
|
|
4020
4020
|
_handleBreak() {
|
|
4021
4021
|
this._breaks++;
|
|
4022
4022
|
const now = Date.now();
|
|
4023
|
-
if (now - this._lastBreakNarrativeTime >
|
|
4023
|
+
if (now - this._lastBreakNarrativeTime > 6e4) {
|
|
4024
4024
|
this._lastBreakNarrativeTime = now;
|
|
4025
4025
|
const reactions = this.script.stage1Reactions;
|
|
4026
4026
|
const line = reactions[this._narrativeIndex % reactions.length];
|
|
@@ -4060,7 +4060,7 @@ class MotionStage {
|
|
|
4060
4060
|
const introLines = this.script.stage2Intro;
|
|
4061
4061
|
for (let i = 0; i < introLines.length; i++) {
|
|
4062
4062
|
this.bus.emit("narrative:show", introLines[i]);
|
|
4063
|
-
await this._wait(
|
|
4063
|
+
await this._wait(4500);
|
|
4064
4064
|
}
|
|
4065
4065
|
this.bus.emit("narrative:clear");
|
|
4066
4066
|
await this._wait(1e3);
|
|
@@ -4115,7 +4115,7 @@ class MotionStage {
|
|
|
4115
4115
|
// โโโ Internal โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
4116
4116
|
_handleFade() {
|
|
4117
4117
|
const now = Date.now();
|
|
4118
|
-
if (now - this._lastFadeNarrativeTime >
|
|
4118
|
+
if (now - this._lastFadeNarrativeTime > 6e4) {
|
|
4119
4119
|
this._lastFadeNarrativeTime = now;
|
|
4120
4120
|
const reactions = this.script.stage2Reactions;
|
|
4121
4121
|
const line = reactions[this._narrativeIndex % reactions.length];
|
|
@@ -4159,7 +4159,7 @@ class RhythmStage {
|
|
|
4159
4159
|
const introLines = this.script.stage3Intro;
|
|
4160
4160
|
for (let i = 0; i < introLines.length; i++) {
|
|
4161
4161
|
this.bus.emit("narrative:show", introLines[i]);
|
|
4162
|
-
await this._wait(
|
|
4162
|
+
await this._wait(4500);
|
|
4163
4163
|
}
|
|
4164
4164
|
this.bus.emit("narrative:clear");
|
|
4165
4165
|
await this._wait(1e3);
|
|
@@ -4219,7 +4219,7 @@ class RhythmStage {
|
|
|
4219
4219
|
}
|
|
4220
4220
|
_showReaction() {
|
|
4221
4221
|
const now = Date.now();
|
|
4222
|
-
if (now - this._lastNarrativeTime >
|
|
4222
|
+
if (now - this._lastNarrativeTime > 6e4) {
|
|
4223
4223
|
this._lastNarrativeTime = now;
|
|
4224
4224
|
const reactions = this.script.stage3Reactions;
|
|
4225
4225
|
const line = reactions[this._narrativeIndex % reactions.length];
|
|
@@ -4683,7 +4683,7 @@ class GameController {
|
|
|
4683
4683
|
this.hiddenEntry = null;
|
|
4684
4684
|
this._startAnticipationTremor();
|
|
4685
4685
|
(_b2 = this.shrine) == null ? void 0 : _b2.show();
|
|
4686
|
-
await ((_c = this.narrative) == null ? void 0 : _c.showSequence(this.script.entryConfirmation,
|
|
4686
|
+
await ((_c = this.narrative) == null ? void 0 : _c.showSequence(this.script.entryConfirmation, 4200));
|
|
4687
4687
|
(_d = this.narrative) == null ? void 0 : _d.clear();
|
|
4688
4688
|
this._stopAnticipationTremor();
|
|
4689
4689
|
await this._wait(800);
|
|
@@ -4799,7 +4799,7 @@ class GameController {
|
|
|
4799
4799
|
(_b2 = (_a2 = this.config.callbacks).onStageComplete) == null ? void 0 : _b2.call(_a2, this.fsm.state, result);
|
|
4800
4800
|
}
|
|
4801
4801
|
const successLines = eggIndex === 0 ? this.script.stage1Success : eggIndex === 1 ? this.script.stage2Success : this.script.stage3Success;
|
|
4802
|
-
await ((_c = this.narrative) == null ? void 0 : _c.showSequence(successLines,
|
|
4802
|
+
await ((_c = this.narrative) == null ? void 0 : _c.showSequence(successLines, 4500));
|
|
4803
4803
|
(_d = this.narrative) == null ? void 0 : _d.clear();
|
|
4804
4804
|
await this._wait(800);
|
|
4805
4805
|
if (this.threeRenderer) {
|
|
@@ -4880,7 +4880,7 @@ class GameController {
|
|
|
4880
4880
|
(_c = this.shrine) == null ? void 0 : _c.hideAll();
|
|
4881
4881
|
await this._wait(1e3);
|
|
4882
4882
|
(_d = this.eggRenderer) == null ? void 0 : _d.startFinale();
|
|
4883
|
-
await ((_e = this.narrative) == null ? void 0 : _e.showSequence(this.script.finale,
|
|
4883
|
+
await ((_e = this.narrative) == null ? void 0 : _e.showSequence(this.script.finale, 5e3));
|
|
4884
4884
|
(_f = this.narrative) == null ? void 0 : _f.clear();
|
|
4885
4885
|
await this._wait(4e3);
|
|
4886
4886
|
this.fsm.transitionTo("results");
|