A dark, mysterious five-act ARG built around hidden archives and forgotten witnesses.

Viewing files at commit 58283b6a8b63Commit detailsView latest

assets/js/pages/acts.js 333 lines · 10.9 KB · javascript
1
// All five acts with multiple puzzles and storyline
2
3
const Acts = {
4
  data: [
5
    {
6
      id: 'act1',
7
      title: 'ACT I: THE NAMING',
8
      subtitle: 'Who watches the archive?',
9
      acts_completed: 0,
10
      sections: [
11
        {
12
          id: 'intro',
13
          type: 'text',
14
          content: `You receive a message through channels that don't officially exist:
15
16
"The archive is looking for a witness. Someone to remember what others have forgotten. If you can answer the first question, the door will open."
17
18
The message cuts off. Nothing else. Just waiting.`
19
        },
20
        {
21
          id: 'gate',
22
          type: 'puzzle',
23
          question: 'What is the name of one who sees and testifies to truth?',
24
          answer: 'WITNESS',
25
          hints: [
26
            'Someone who observes.',
27
            'A person present at an event.',
28
            'W-I-T-N-E-S-S'
29
          ],
30
          successMessage: 'The first door opens. You have been acknowledged by the archive.',
31
          rewards: [
32
            { type: 'item', id: 'key_witness', name: 'Fragment: The Witness', description: 'A fragment of understanding.' },
33
            { type: 'evidence', id: 'letter_1', name: 'First Message', description: 'The initial contact from the archive.' }
34
          ]
35
        },
36
        {
37
          id: 'ledger_discovery',
38
          type: 'text',
39
          content: `Inside, you find a room filled with ledgers. Thousands of them. Each one contains a name that has been erased from all public records.
40
41
The pages are yellowed. Some are water-damaged. Others have been deliberately redacted. But patterns emerge—connections between names, places, dates.
42
43
One ledger in particular catches your eye. It's labeled "THE FORGOTTEN" and opens to a page marked with a faded ribbon.`
44
        },
45
        {
46
          id: 'ledger_puzzle',
47
          type: 'puzzle',
48
          question: 'What are things that are not remembered?',
49
          answer: 'FORGOTTEN',
50
          hints: [
51
            'The opposite of remembered.',
52
            'Lost to time.',
53
            'F-O-R-G-O-T-T-E-N'
54
          ],
55
          successMessage: 'The ledger opens. Its secrets begin to reveal themselves.',
56
          rewards: [
57
            { type: 'item', id: 'ledger_fragment', name: 'Ledger Page', description: 'A page from "The Forgotten".' },
58
            { type: 'evidence', id: 'names_list', name: 'List of Names', description: 'Erased from history. Never to be known.' }
59
          ]
60
        },
61
        {
62
          id: 'encrypted_message',
63
          type: 'text',
64
          content: `At the bottom of the page, you find text in a strange cipher:
65
66
THJ PWKZRJ WJNJNGJWU
67
68
Next to it, a handwritten note: "Caesar knew many secrets. His shift was always three."
69
70
This is your first real test.`
71
        },
72
        {
73
          id: 'cipher_puzzle',
74
          type: 'interactive',
75
          tool: 'caesar_decoder',
76
          encrypted: 'THJ PWKZRJ WJNJNGJWU',
77
          shift: 3,
78
          hint: 'The Roman leader Caesar used a simple cipher to protect his messages. Shift each letter by 3 places backward.',
79
          successMessage: 'You have decrypted the message. Continue reading.',
80
          rewards: [
81
            { type: 'item', id: 'cipher_knowledge', name: 'Caesar Cipher Knowledge', description: 'Understanding of ancient encryption methods.' }
82
          ]
83
        },
84
        {
85
          id: 'decrypted_message',
86
          type: 'text',
87
          content: `The cipher reveals:
88
89
"THE ARCHIVE REMEMBERS"
90
91
Below the decrypted text, more handwriting:
92
93
"Every name in these ledgers was someone. Every crossed-out line was a life. The archive does not forget. It merely waits for someone to bear witness. 
94
95
Will you remember them?
96
97
- The First Keeper"`
98
        },
99
        {
100
          id: 'message_puzzle',
101
          type: 'puzzle',
102
          question: 'What does the archive do?',
103
          answer: 'THE ARCHIVE REMEMBERS',
104
          hints: [
105
            'A statement about the archive\'s purpose.',
106
            'THE ARCHIVE _______',
107
            'THE ARCHIVE REMEMBERS'
108
          ],
109
          successMessage: 'Act I complete. You have taken the first step.',
110
          rewards: [
111
            { type: 'item', id: 'act1_complete', name: 'Act I Completion', description: 'You have witnessed the first truth.' },
112
            { type: 'unlock', id: 'act2', section: 'act2' }
113
          ]
114
        }
115
      ]
116
    },
117
    {
118
      id: 'act2',
119
      title: 'ACT II: THE VAULT',
120
      subtitle: 'Where are the forbidden names kept?',
121
      acts_completed: 1,
122
      sections: [
123
        {
124
          id: 'intro',
125
          type: 'text',
126
          content: `Now that you have proven yourself a witness, the archive grants access to deeper layers.
127
128
A message appears:
129
130
"The names must be stored somewhere. Protected. Hidden from those who would erase them further.
131
132
There is a vault. Only the worthy may enter.
133
134
The code is hidden in silence."`
135
        },
136
        {
137
          id: 'vault_puzzle',
138
          type: 'puzzle',
139
          question: 'What is the absence of sound called?',
140
          answer: 'SILENCE',
141
          hints: [
142
            'The lack of noise.',
143
            'Quiet. Still. Absolute quiet.',
144
            'S-I-L-E-N-C-E'
145
          ],
146
          successMessage: 'The vault recognition system accepts your answer.',
147
          rewards: [
148
            { type: 'item', id: 'vault_access', name: 'Vault Access Card', description: 'Permission to enter the restricted sections.' }
149
          ]
150
        },
151
        {
152
          id: 'vault_interior',
153
          type: 'text',
154
          content: `Inside the vault, rows upon rows of metal filing cabinets stretch into darkness. Each drawer is labeled with a number, a date, a location.
155
156
You notice one cabinet is different. Its label glows faintly:
157
158
"DEPARTMENT OF INTERNAL AFFAIRS - 1987 - CLEARANCE REQUIRED"
159
160
Next to it, a code lock with illuminated buttons.`
161
        },
162
        {
163
          id: 'number_sequence',
164
          type: 'puzzle',
165
          question: 'What is the next number in this sequence? 1, 1, 2, 3, 5, 8, 13, ?, ?',
166
          answer: '21',
167
          alternate_answers: ['21, 34'],
168
          hints: [
169
            'This is a famous mathematical sequence.',
170
            'Each number is the sum of the two before it.',
171
            'Fibonacci sequence: 21 is next.'
172
          ],
173
          successMessage: 'The cabinet drawer slides open.',
174
          rewards: [
175
            { type: 'evidence', id: 'classified_file', name: 'Classified File', description: 'Contents: REDACTED' }
176
          ]
177
        },
178
        {
179
          id: 'file_discovery',
180
          type: 'text',
181
          content: `The drawer contains a single manila envelope marked with a red stamp: EYES ONLY.
182
183
Inside, a stack of photographs. They show a door. Not a metaphorical door—an actual, physical door in what appears to be a basement or bunker.
184
185
The photographs are dated 1987. The last one has a single word written on the back in faded ink:
186
187
DOOR
188
189
And then, a question in different handwriting:
190
191
"What is on the other side? What did they hide behind the DOOR?"`
192
        }
193
      ]
194
    },
195
    {
196
      id: 'act3',
197
      title: 'ACT III: THE CIPHER',
198
      subtitle: 'What message did they try to hide?',
199
      acts_completed: 2,
200
      sections: [
201
        {
202
          id: 'intro',
203
          type: 'text',
204
          content: `The photographs lead you deeper into the archive's restricted records section.
205
206
You discover a series of documents, each one encrypted with different methods. The archive seems to have tested many cipher techniques over the decades.
207
208
This is where the real secrets are kept.`
209
        }
210
      ]
211
    },
212
    {
213
      id: 'act4',
214
      title: 'ACT IV: THE WITNESS',
215
      subtitle: 'What is the truth?',
216
      acts_completed: 3,
217
      sections: [
218
        {
219
          id: 'intro',
220
          type: 'text',
221
          content: `You've gathered the pieces. You've decrypted the messages. You've found the evidence.
222
223
But now you face a choice: What will you do with what you know?
224
225
The archive presents its final test: A choice between truth and mercy, between exposure and silence.`
226
        }
227
      ]
228
    },
229
    {
230
      id: 'act5',
231
      title: 'ACT V: REMEMBER',
232
      subtitle: 'Who are you now?',
233
      acts_completed: 4,
234
      sections: [
235
        {
236
          id: 'intro',
237
          type: 'text',
238
          content: `This is the final act.
239
240
Everything has led here. Every cipher decoded. Every name remembered. Every truth uncovered.
241
242
Now you must speak the final phrase—the one that binds you to the archive forever.
243
244
To speak it is to become part of what you have discovered. To remember is to become a keeper of these secrets.
245
246
Are you ready?`
247
        }
248
      ]
249
    }
250
  ],
251
  
252
  render(actId) {
253
    const act = this.data.find(a => a.id === actId);
254
    if (!act) return `<p>Act not found.</p>`;
255
    
256
    let html = `
257
      <section class="hero act-hero">
258
        <div class="act-indicator">ACT ${act.acts_completed + 1} / 5</div>
259
        <h1>${act.title}</h1>
260
        <p class="lead">${act.subtitle}</p>
261
      </section>
262
    `;
263
    
264
    for (let section of act.sections) {
265
      html += this.renderSection(section);
266
    }
267
    
268
    return html;
269
  },
270
  
271
  renderSection(section) {
272
    switch (section.type) {
273
      case 'text':
274
        return `
275
          <section class="panel story-panel">
276
            <p class="panel-content">${section.content.split('\n\n').join('</p><p class="panel-content">')}</p>
277
          </section>
278
        `;
279
      
280
      case 'puzzle':
281
        return `
282
          <section class="panel puzzle-panel" data-puzzle-id="${section.id}">
283
            <p class="panel-title">PUZZLE: ${section.id.toUpperCase()}</p>
284
            <p class="puzzle-question">${section.question}</p>
285
            <form class="puzzle-form" data-puzzle-id="${section.id}">
286
              <input type="text" placeholder="Your answer" autocomplete="off" />
287
              <button type="submit">Submit Answer</button>
288
              <button type="button" class="hint-btn">Get Hint</button>
289
            </form>
290
            <p class="puzzle-result" aria-live="polite"></p>
291
          </section>
292
        `;
293
      
294
      case 'interactive':
295
        return `
296
          <section class="panel interactive-panel" data-tool="${section.tool}">
297
            <p class="panel-title">DECRYPTION TOOL</p>
298
            <p>Encrypted text: <code>${section.encrypted}</code></p>
299
            <p>${section.hint}</p>
300
            <div id="tool-${section.id}"></div>
301
          </section>
302
        `;
303
      
304
      default:
305
        return '';
306
    }
307
  },
308
  
309
  attach() {
310
    // Attach puzzle handlers
311
    document.querySelectorAll('.puzzle-form').forEach(form => {
312
      form.addEventListener('submit', (e) => {
313
        e.preventDefault();
314
        const puzzleId = form.dataset.puzzleId;
315
        const answer = form.querySelector('input').value;
316
        this.checkPuzzle(puzzleId, answer);
317
      });
318
      
319
      form.querySelector('.hint-btn').addEventListener('click', () => {
320
        const puzzleId = form.dataset.puzzleId;
321
        this.showHint(puzzleId);
322
      });
323
    });
324
  },
325
  
326
  checkPuzzle(puzzleId, answer) {
327
    // Implemented in UI handler
328
  },
329
  
330
  showHint(puzzleId) {
331
    // Implemented in UI handler
332
  }
333
};