JavaScript must be enabled to play.
Browser lacks capabilities required to play.
Upgrade or switch to another browser.
Loading…
<div id="video-intro-screen"> <video id="intro-video" playsinline preload="auto"> <source src="video/intro.mp4" type="video/mp4"> </video> <div id="video-overlay"> <div id="sound-indicator"> <svg id="headphones-icon" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2"> <path d="M3 18v-6a9 9 0 0 1 18 0v6"></path> <path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"></path> </svg> <span id="sound-text">sound on</span> </div> <button id="video-start-button"> <span id="video-scramble-text">œß¥ŽΣπ</span> </button> </div> </div> <script> (function() { const video = document.getElementById('intro-video'); const overlay = document.getElementById('video-overlay'); const startButton = document.getElementById('video-start-button'); const scrambleEl = document.getElementById('video-scramble-text'); const soundIndicator = document.getElementById('sound-indicator'); const finalText = 'START'; const characters = 'œß¥ŽΣπ∆©ƒ∂åΩ≈ç√∫˜µ≤≥÷¡™£¢∞§¶•ªº'; let frame = 0; const totalFrames = 20; // *** TIMING CONTROLS *** const TRANSITION_DELAY = 1000; // Delay before advancing to next passage (in milliseconds) // 1000 = 1 second, 2000 = 2 seconds, 500 = 0.5 seconds, etc. // Scramble text animation function scramble() { if (frame < totalFrames) { let scrambled = ''; for (let i = 0; i < finalText.length; i++) { if (frame > (i * totalFrames / finalText.length)) { scrambled += finalText[i]; } else { scrambled += characters[Math.floor(Math.random() * characters.length)]; } } scrambleEl.textContent = scrambled; frame++; setTimeout(scramble, 50); } else { scrambleEl.textContent = finalText; // Fade in the sound indicator after scramble completes setTimeout(function() { soundIndicator.style.opacity = '1'; }, 300); } } // Start scrambling after delay setTimeout(scramble, 500); // Start button click handler startButton.addEventListener('click', function() { overlay.style.opacity = '0'; overlay.style.pointerEvents = 'none'; video.play(); // Stop ambient sound if it exists if (window.ambientHum) { ambientHum.pause(); ambientHum.currentTime = 0; } }); // When video ends, wait before advancing to Intro passage video.addEventListener('ended', function() { console.log('Video ended! Waiting', TRANSITION_DELAY, 'ms before transition...'); setTimeout(function() { console.log('Now transitioning to Intro passage'); // Hide the video screen before transitioning document.getElementById('video-intro-screen').style.display = 'none'; SugarCube.Engine.play('Intro'); }, TRANSITION_DELAY); }); })(); </script> <style> #video-intro-screen { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: #000; display: flex; justify-content: center; align-items: center; overflow: hidden; } #intro-video { width: 100%; height: 100%; object-fit: contain; } #video-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 2rem; transition: opacity 0.5s ease; } #sound-indicator { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; opacity: 0; transition: opacity 1s ease; } #headphones-icon { animation: pulse 2s ease-in-out infinite; } #sound-text { font-family: 'Glass TTY VT220', monospace; color: white; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.1em; } @keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.6; transform: scale(1.1); } } #video-start-button { font-family: 'Glass TTY VT220', monospace; font-size: 1.5rem; color: black; background-color: #00ff00; border: none; padding: 0.6em 2em; border-radius: 0.25em; cursor: pointer; text-transform: uppercase; text-shadow: 0 0 2px #00ff00; box-shadow: 0 0 10px #00ff00; transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; line-height: 1.2; animation: flicker 2.5s infinite; } #video-start-button:hover { background-color: #00cc00; box-shadow: 0 0 15px #00ff00; } @keyframes flicker { 0% { opacity: 1; transform: none; } 3% { opacity: 0.3; transform: translate(-1px, 1px) scale(1.01); } 5% { opacity: 0.8; transform: translate(1px, -2px) scale(0.98); } 8% { opacity: 0.2; transform: translate(-1px, 1px) scale(1.02); } 10% { opacity: 1; transform: none; } 13% { opacity: 0.5; transform: translate(2px, 0) scale(1.03); } 16% { opacity: 1; transform: none; } 23% { opacity: 0.6; transform: translate(0, 2px) scale(0.97); } 26% { opacity: 0.3; transform: translate(-2px, -1px) scale(1.02); } 30% { opacity: 1; transform: none; } 35% { opacity: 0.4; transform: translate(1px, 1px) scale(1.01); } 100% { opacity: 1; transform: none; } } </style>
<div class="PlayerOnboard"> <div id="typewriter-container"> <p id="para1" class="typewriter-text" style="display: none;"></p> <p id="final-words" class="typewriter-text" style="display: none;"></p> </div> <script> // Start playerOnboard audio when Intro passage loads if (window.playerOnboard) { playerOnboard.play(); } setTimeout(function() { (function() { const paragraphs = [ "You've been handpicked to join the unit... Congratulations?", "Modern inelligence requires modern methods... This is a hybrid, off-books team.", "No one on this team is siloed. Do not stay in your lane.", "Field work and analysis are blended in this lean, agile unit.", "Before you launch into your assignment, you will go to The Farm for specialized training.", "Accessing your training scenario is the first test of your tradecraft and system penetration skills.", "If you gain access, HQ will need you at the ready 24/7 via our secure Telegram messaging system.", "Download and install the Telegram app on your agency issued mobile device now.", "Keep comms open.", "Stay vigilant.", "Follow CONTROL's instrucitons.", "Practice good tradecraft.", "Trust no one." ]; const finalWords = ["INTELLIGENCE", "NEVER", "SLEEPS"]; let currentParagraph = 0; let currentWord = 0; const typeSpeed = 50; const pauseBeforeFade = 1200; const fadeOutDuration = 500; const pauseBetweenWords = 200; function typeWriter(element, text, callback) { if (!element) { console.error("Element not found!"); return; } element.style.display = "block"; element.innerHTML = ""; let i = 0; function type() { if (i < text.length) { // Check for pause marker (...) if (text.substr(i, 3) === '...') { i += 3; // Skip the ... element.innerHTML += '...'; // Add the ellipsis setTimeout(type, 1200); // Pause for 1200ms (adjustable) } else { element.innerHTML += text.charAt(i); i++; setTimeout(type, typeSpeed); } } else if (callback) { setTimeout(callback, pauseBeforeFade); } } type(); } function fadeOut(element, callback) { element.style.transition = "opacity " + fadeOutDuration + "ms"; element.style.opacity = "0"; setTimeout(function() { element.style.display = "none"; element.style.opacity = "1"; if (callback) callback(); }, fadeOutDuration); } function startNextParagraph() { if (currentParagraph < paragraphs.length) { const element = document.getElementById("para1"); typeWriter(element, paragraphs[currentParagraph], function() { fadeOut(element, function() { currentParagraph++; startNextParagraph(); }); }); } else { startFinalWords(); } } function typeWord(element, word, callback) { element.style.display = "block"; element.innerHTML = ""; let i = 0; function type() { if (i < word.length) { element.innerHTML += word.charAt(i); i++; setTimeout(type, typeSpeed * 2); } else if (callback) { setTimeout(callback, pauseBeforeFade); } } type(); } function scrambleWord(element, word, callback) { const characters = 'œß¥ŽΣπ∆©ƒ∂åΩ≈ç√∫˜µ≤≥÷¡™£¢∞§¶•ªºABCDEFGHIJKLMNOPQRSTUVWXYZ'; let frame = 0; const totalFrames = 20; function scramble() { if (frame < totalFrames) { let scrambled = ''; for (let i = 0; i < word.length; i++) { scrambled += characters[Math.floor(Math.random() * characters.length)]; } element.innerHTML = scrambled; frame++; setTimeout(scramble, 50); } else { fadeOut(element, callback); } } scramble(); } function startFinalWords() { if (currentWord < finalWords.length) { const element = document.getElementById("final-words"); const word = finalWords[currentWord]; if (word === "SLEEPS") { typeWord(element, word, function() { setTimeout(function() { scrambleWord(element, word, function() { SugarCube.Engine.play('PlayerDataCapture'); }); }, 500); }); } else { typeWord(element, word, function() { fadeOut(element, function() { currentWord++; setTimeout(startFinalWords, pauseBetweenWords); }); }); } } } startNextParagraph(); })(); }, 100); </script> </div>
<div class="login-terminal"> <h2>SECURE TERMINAL :: CONTROL ACCESS REQUEST FORM<span class="blink-cursor"></span></h2> <div class="warning-message"> <span class="stop-text">STOP!</span> YOU CAN NOT PROCEED WITHOUT HAVING TELEGRAM INSTALLED ON YOUR AGENCY ISSUED SECURE MOBILE DEVICE. YOU WILL ALSO NEED YOUR TELEGRAM ID. <small class="field-help">Don't know your ID? Message <a href="https://t.me/userinfobot" target="_blank">@userinfobot</a> on Telegram</small> </div> <div class="briefing-text"> Your CONTROL handler sends encrypted mission briefings, files, images, audio, video and other intelligence directly to your secure Telegram account. </div> <p class="clearance">SECURITY CLEARANCE REQUIRED - COMPLETE DATA COLLECTION FORM BELOW</p> <<textbox "$playerFirstName" "" autofocus>> <label>First Name* (Required)</label> <<textbox "$playerLastName" "">> <label>Last Name (Optional)</label> <<textbox "$playerPhone" "">> <label>Phone Number* (Required - FORMAT: +12025551212)</label> <<textbox "$playerEmail" "">> <label>Email* (Required)</label> <<textbox "$telegramUserID" "">> <label>Telegram User ID* (Required)</label> <div style="margin-top: 20px;"> <<checkbox "$agreedToComms" false true id="agree-checkbox" disabled>> I have <span class="read-trigger" id="read-trigger">READ</span> the Terms of Service and Privacy Policy and I agree to receive game communications via Telegram/SMS/Email.* </div> <p style="margin-top: 20px;"> ⚠️ IMMEDIATE ACTION REQUIRED - To proceed you must <span class="read-trigger" id="activate-comms-trigger" style="color: #ff0000; text-shadow: 0 0 5px #ff0000;">ACTIVATE</span> comms with CONTROL ⚠️ </p> <div id="status" class="status-message"></div> <div class="popover" id="terms-popover"> <h3>TERS OF SERVICE & PRIVACY POLICY</h3> <p><strong>Terms of Service:</strong> This is an interactive fiction game. By participating, you agree to receive fictional mission briefings and game content via Telegram, SMS, and email. You may unsubscribe at any time.</p> 1. SMS - By opting-in, you agree to receive messages directly related to the gameplay of the Wilderness Of Mirrors espionage roleplay game. You will receive instructions, missions, intelligence, images, audio and video briefings from "CONTROL" 2. You can cancel the SMS service at any time. Just text "STOP" to the short code. After you send the SMS message "STOP" to us, we will send you an SMS message to confirm that you have been unsubscribed. 3. If you are experiencing issues with the messaging program you can reply with the keyword HELP for more assistance. 4. Carriers are not liable for delayed or undelivered messages. 5. As always, message and data rates may apply for any messages sent to you from us and to us from you. 6. If you have any questions regarding privacy, please read our privacy policy below. <p><strong>Privacy Policy:</strong> Your contact information will be used solely for delivering game content. We do not sell or share your data with third parties. Your information is stored securely and will be deleted upon request.</p> <h2>What happens to your data</h2> <ul> <li>Your phone number will receive mission-critical SMS/MMS/voice messages via Twilio</li> <li>You will also receive mission-critical SMS/MMS/voice messages via Telegram</li> <li>Your email may receive intelligence briefings and game updates</li> <li>Data stored securely for playtest duration only</li> <li>You can text STOP to opt-out anytime</li> <li>All playtest data deleted within 30 days of playtest conclusion</li> <li>Your data will NOT be shared with third parties (except Twilio for message delivery)</li> </ul> <p class="read-confirmation">You have reviewed the terms. Checkbox now enabled.</p> <div> <button class="close-popover" id="close-popover">✖ CLOSE</button> </div> </div> <div class="popover" id="comms"> <h3>📡 ENCRYPTED CHANNEL INITIALIZATION</h3> <ol style="text-align: left; line-height: 1.8; font-size: 0.9em;"> <li>On your mobile device, open the Telegram app</li> <li>Search for: <strong>@CONTROL_handler_bot</strong></li> <li>Tap the bot, then tap <strong>START</strong></li> <li>Your encrypted transmission will arrive immediately</li> </ol> <p style="font-size: 0.8em; color: #ff0000; text-align: center;">Note: The bot must be started from the Telegram mobile app, not desktop.</p> <div style="text-align: center; border-top: 1px solid #00ff00; padding-top: 15px; margin-top: 15px;"> <label><input type="checkbox" id="bot-started-checkbox"> I have started the bot in Telegram</label> <button id="final-activate-button" class="close-popover" style="display:none; background: #ff0000; color: white; margin-top: 15px;">⚡ ESTABLISH SECURE CONNECTION</button> </div> <button class="close-popover" id="close-comms" style="background: transparent; color: #00ff00; border: 1px solid #00ff00; margin-top: 10px; font-size: 0.8em;">CANCEL</button> </div> </div> <style> .warning-message { font-family: monospace; font-weight: bold; color: #00ff00; text-align: center; line-height: 1.6; margin: 1.5em 0; } .stop-text { color: #ff0000; font-weight: bold; animation: blink-warning 1s infinite; } @keyframes blink-warning { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } } .read-trigger { color: #00ff00; font-weight: bold; text-decoration: underline; cursor: pointer; position: relative; text-shadow: 0 0 5px #00ff00; } .popover { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #000; border: 2px solid #00ff00; padding: 1.5em; max-width: 600px; max-height: 80vh; overflow-y: auto; z-index: 1000; color: #00ff00; box-shadow: 0 0 20px rgba(0, 255, 0, 0.5); } .popover h3 { color: #00ff00; margin-top: 0; text-align: center; border-bottom: 1px solid #00ff00; padding-bottom: 0.5em; } .close-popover { display: block; width: 100%; margin-top: 1.5em; padding: 0.8em; background: #00ff00; color: #000; border: none; font-weight: bold; cursor: pointer; } #agree-checkbox:disabled { opacity: 0.5; cursor: not-allowed; } </style> <<script>> window.registerAgent = function() { $('#status').removeClass('error-message').html('🔐 Establishing encrypted connection...'); const agentData = { firstName: State.variables.playerFirstName, lastName: State.variables.playerLastName || '', phone: State.variables.playerPhone, email: State.variables.playerEmail, telegramUserID: State.variables.telegramUserID, status: 'Active', consent: State.variables.agreedToComms, timestamp: new Date().toISOString() }; fetch('https://hook.us2.make.com/47gwtl4no0ic4evy3csqthvnhjdubs2j', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(agentData) }) .then(response => { if (!response.ok) throw new Error('HTTP error ' + response.status); State.variables.agentActivated = true; Engine.play('RegistrationSuccess'); }) .catch(error => { $('#status').html('❌ CONNECTION FAILED - Check info and try again'); }); }; $(document).on(':passageend', function() { let hasRead = false; // READ hover logic $('#read-trigger').off('mouseenter').on('mouseenter', function() { $('#terms-popover').fadeIn(300); }); $('#close-popover').off('click').on('click', function() { hasRead = true; $('#agree-checkbox').prop('disabled', false); $('#terms-popover').fadeOut(300); }); // ACTIVATE hover logic $('#activate-comms-trigger').off('mouseenter').on('mouseenter', function() { $('#comms').fadeIn(300); }); $('#close-comms').off('click').on('click', function() { $('#comms').fadeOut(300); }); // Checkbox button toggle $(document).off('change', '#bot-started-checkbox').on('change', '#bot-started-checkbox', function() { if($(this).is(':checked')) { $('#final-activate-button').show(); } else { $('#final-activate-button').hide(); } }); // Webhook trigger $('#final-activate-button').off('click').on('click', function() { $('#comms').fadeOut(300); window.registerAgent(); }); }); <</script>>
<div class="PlayerOnboard"> <div id="registration-sequence-container"> <audio id="bgm-detective" src="sounds/Detective.m4a" preload="auto"></audio> <div id="intelligence-badge-container"> <img src="Images/DIAU.png" alt="Intelligence Unit Badge" id="intel-badge"> </div> <p id="reg-para" class="typewriter-text" style="display: none;"></p> </div> <style> .PlayerOnboard { background-color: #000; min-height: 100vh; display: flex; flex-direction: column; justify-content: center; align-items: center; overflow: hidden; } #registration-sequence-container { text-align: center; width: 80%; } .typewriter-text { font-family: 'Glass TTY VT220', monospace; color: #00ff00; font-size: 2em; text-shadow: 0 0 5px #00ff00; margin: 0; line-height: 1.5; white-space: pre-wrap; } #intelligence-badge-container { margin-bottom: 2rem; opacity: 0; transition: transform 18s ease-in-out, opacity 1.5s ease-in-out; transform: scale(1.5); } #intel-badge { max-width: 250px; height: auto; filter: drop-shadow(0 0 5px rgba(0, 255, 0, 0.5)); } .badge-glitch { animation: image-shred 0.2s steps(2) infinite; } @keyframes image-shred { 0% { clip-path: inset(20% 0 50% 0); filter: hue-rotate(90deg) brightness(2); transform: translate(-8px, 4px); } 50% { clip-path: inset(40% 0 10% 0); filter: hue-rotate(-90deg) contrast(3); transform: translate(8px, -4px); } 100% { opacity: 0; } } /* UPDATED: Violent Jitter for the final collapse */ .glitch-jitter { display: inline-block; animation: jitter 0.05s infinite; } @keyframes jitter { 0% { transform: translate(0); } 20% { transform: translate(-4px, 2px); filter: contrast(200%); } 40% { transform: translate(4px, -2px); } 60% { transform: translate(-2px, -4px); filter: hue-rotate(10deg); } 80% { transform: translate(2px, 4px); } 100% { transform: translate(0); } } .cursor-char { display: inline; color: #00ff00; animation: simple-blink 1s steps(2, start) infinite; } @keyframes simple-blink { to { visibility: hidden; } } </style> <script> (function() { const sequence = [ { text: "CLEARANCE GRANTED", type: "scramble", blink: true }, { text: "YOUR MISSION LIES ELSEWHERE", type: "type" }, { text: "KEEP TELEGRAM COMMS OPEN", type: "type" }, { text: "STANDBY FOR INSTRUCTION FROM CONTROL", type: "type" }, { text: "FOLLOW THE INSTRUCTIONS CAREFULLY", type: "type" }, { text: "WE ARE FAST-TRACKING YOUR ACTIVATION", type: "type" }, { text: "TRACKING MULTIPLE VECTORS IN THE THREAT MATRIX", type: "type" }, { text: "WATCH YOUR SIX", type: "type" }, { text: "END OF TRANSMISSION", type: "final" } ]; let step = 0; const target = document.getElementById("reg-para"); const badgeContainer = document.getElementById("intelligence-badge-container"); const badgeImage = document.getElementById("intel-badge"); const audio = document.getElementById("bgm-detective"); let isDying = false; let finalRedMode = false; audio.volume = 0.5; audio.play().catch(e => console.log("Click page to start audio.")); setTimeout(() => { badgeContainer.style.opacity = "1"; badgeContainer.style.transform = "scale(1.1)"; }, 500); function glitchLoop() { if (!isDying) return; const rand = Math.random(); if (finalRedMode) { if (rand > 0.92) { target.style.opacity = "0.5"; } else if (rand > 0.85) { target.style.opacity = "0.15"; } else { target.style.opacity = "0"; } setTimeout(glitchLoop, Math.random() * 600 + 100); } else { if (rand > 0.7) { target.style.opacity = "1"; } else if (rand > 0.3) { target.style.opacity = "0"; } else { target.style.opacity = "0.4"; } setTimeout(glitchLoop, Math.random() * 150 + 40); } } function runSequence() { if (step >= sequence.length) return; const current = sequence[step]; target.classList.remove("glitch-jitter"); target.style.transition = "none"; target.style.opacity = "1"; target.style.display = "block"; target.innerHTML = ""; if (current.type === "scramble") { scrambleEffect(target, current.text, function() { if (current.blink) target.innerHTML += ' <span class="cursor-char">█</span>'; setTimeout(nextStep, 2500); }); } else if (current.type === "type" || current.type === "final") { typeEffect(target, current.text, function() { if (current.type === "final") { setTimeout(() => scrambleOff(target, current.text), 2000); } else { setTimeout(nextStep, 2500); } }); } } function nextStep() { target.style.transition = "opacity 800ms"; target.style.opacity = "0"; setTimeout(() => { step++; runSequence(); }, 800); } function typeEffect(element, text, callback) { let i = 0; function type() { if (i < text.length) { element.innerHTML += text.charAt(i); let currentDelay = 50; if (text.charAt(i) === ".") { currentDelay = 500; } i++; setTimeout(type, currentDelay); } else { callback(); } } type(); } function scrambleEffect(element, word, callback) { const chars = 'œß¥ŽΣπ∆©ƒ∂åΩ≈ç√∫˜µ≤≥÷¡™£¢∞§¶•ªºABCDEFGHIJKLMNOPQRSTUVWXYZ'; let frame = 0; function scramble() { if (frame < 30) { let res = ''; for (let i = 0; i < word.length; i++) { res += chars[Math.floor(Math.random() * chars.length)]; } element.innerHTML = res; frame++; setTimeout(scramble, 40); } else { element.innerHTML = word; callback(); } } scramble(); } function scrambleOff(element, word) { isDying = true; glitchLoop(); element.classList.add("glitch-jitter"); badgeImage.classList.add("badge-glitch"); const chars = 'œß¥ŽΣπ∆©ƒ∂åΩ≈ç√∫˜µ≤≥÷¡™£¢∞§¶•ªº'; let frame = 0; function off() { if (frame < 30) { let res = ''; for (let i = 0; i < word.length; i++) { res += chars[Math.floor(Math.random() * chars.length)]; } element.innerHTML = res; frame++; setTimeout(off, 40); } else { finalRedMode = true; element.style.fontSize = "2.5em"; element.style.fontWeight = "bold"; element.style.color = "#ff0000"; element.style.textShadow = "0 0 15px #ff0000, 0 0 5px #ffffff"; element.innerHTML = "CONNECTION TERMINATED"; badgeContainer.style.display = "none"; const fadeAudio = setInterval(() => { if (audio.volume > 0.1) { audio.volume -= 0.1; } else { audio.pause(); clearInterval(fadeAudio); } }, 100); } } off(); } runSequence(); })(); </script> </div>