Save point: Scene 2 complete - cursor blink, pre-LEARN/LEARN text, keyboard shortcuts (Escape/Backspace)
This commit is contained in:
287
index.html
287
index.html
@@ -90,6 +90,51 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 1s ease;
|
transition: opacity 1s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#blinkCursor {
|
||||||
|
display: none;
|
||||||
|
width: 8px;
|
||||||
|
height: 14px;
|
||||||
|
background-color: #00ff00;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#scene2Text {
|
||||||
|
color: #00ff00;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 2;
|
||||||
|
text-align: center;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#learnBtn {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 5%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 5;
|
||||||
|
padding: 1rem 3rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
background-color: #001100;
|
||||||
|
color: #00ff00;
|
||||||
|
border: 2px solid #00ff00;
|
||||||
|
cursor: pointer;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.5s ease, background-color 0.2s ease;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#learnBtn:hover {
|
||||||
|
background-color: #003300;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -103,9 +148,16 @@
|
|||||||
|
|
||||||
<button id="followBtn">FOLLOW THEM</button>
|
<button id="followBtn">FOLLOW THEM</button>
|
||||||
|
|
||||||
<div id="scene2" class="scene"></div>
|
<div id="scene2" class="scene">
|
||||||
|
<div id="scene2Text"></div>
|
||||||
|
<button id="learnBtn">LEARN</button>
|
||||||
|
<div id="blinkCursor"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// Testing shortcuts state
|
||||||
|
let skipAnimations = false;
|
||||||
|
|
||||||
// Canvas setup for Matrix rain
|
// Canvas setup for Matrix rain
|
||||||
const canvas = document.getElementById('matrixCanvas');
|
const canvas = document.getElementById('matrixCanvas');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
@@ -206,35 +258,108 @@
|
|||||||
}, 16);
|
}, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typewriter text effect
|
// Reusable typewriter function with custom delays
|
||||||
const lines = [
|
// If endCharDelay is provided, speed accelerates from charDelay to endCharDelay
|
||||||
|
function typewriterLines(lines, targetElem, onComplete, charDelay = 60, lineDelay = 500, endCharDelay = null) {
|
||||||
|
let currentLine = 0;
|
||||||
|
let currentChar = 0;
|
||||||
|
let totalChars = 0;
|
||||||
|
let charsTyped = 0;
|
||||||
|
|
||||||
|
// Calculate total characters if using accelerating speed
|
||||||
|
if (endCharDelay !== null) {
|
||||||
|
totalChars = lines.reduce((sum, line) => sum + line.length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDelay() {
|
||||||
|
if (endCharDelay === null || totalChars === 0) return charDelay;
|
||||||
|
// Linear interpolation from charDelay to endCharDelay
|
||||||
|
const progress = charsTyped / totalChars;
|
||||||
|
return charDelay + (endCharDelay - charDelay) * progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tick() {
|
||||||
|
if (skipAnimations) {
|
||||||
|
// Instantly show all remaining text
|
||||||
|
let remainingText = '';
|
||||||
|
for (let i = currentLine; i < lines.length; i++) {
|
||||||
|
remainingText += lines[i];
|
||||||
|
}
|
||||||
|
targetElem.textContent = remainingText;
|
||||||
|
onComplete?.();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentLine >= lines.length) {
|
||||||
|
onComplete?.();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetElem.style.visibility = 'visible';
|
||||||
|
const lineText = lines[currentLine];
|
||||||
|
|
||||||
|
if (currentChar < lineText.length) {
|
||||||
|
targetElem.textContent += lineText[currentChar];
|
||||||
|
currentChar++;
|
||||||
|
charsTyped++;
|
||||||
|
setTimeout(tick, getDelay());
|
||||||
|
} else {
|
||||||
|
currentLine++;
|
||||||
|
currentChar = 0;
|
||||||
|
setTimeout(tick, lineDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scene 1 typewriter
|
||||||
|
const scene1lines = [
|
||||||
"YOU ARE NOT IMAGINING THINGS",
|
"YOU ARE NOT IMAGINING THINGS",
|
||||||
"THE SYNCHRONICITIES YOU ARE EXPERIENCING HAVE ALWAYS BEEN THERE",
|
"THE SYNCHRONICITIES YOU ARE EXPERIENCING HAVE ALWAYS BEEN THERE",
|
||||||
"THE ONLY THING THAT HAS CHANGED IS YOUR AWARENESS OF THEM"
|
"THE ONLY THING THAT HAS CHANGED IS YOUR AWARENESS OF THEM"
|
||||||
];
|
];
|
||||||
let currentLine = 0;
|
let scene1LineIndex = 0;
|
||||||
let currentChar = 0;
|
let scene1Timeouts = [];
|
||||||
|
|
||||||
function typewriter() {
|
function typewriter() {
|
||||||
if (currentLine >= lines.length) {
|
if (scene1LineIndex >= scene1lines.length) {
|
||||||
showButton();
|
showButton();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lineElem = document.getElementById(`line${currentLine + 1}`);
|
const lineElem = document.getElementById(`line${scene1LineIndex + 1}`);
|
||||||
lineElem.style.visibility = 'visible';
|
lineElem.style.visibility = 'visible';
|
||||||
const lineText = lines[currentLine];
|
const lineText = scene1lines[scene1LineIndex];
|
||||||
|
let charIndex = 0;
|
||||||
|
|
||||||
if (currentChar < lineText.length) {
|
function typeChar() {
|
||||||
lineElem.textContent += lineText[currentChar];
|
if (charIndex < lineText.length) {
|
||||||
currentChar++;
|
lineElem.textContent += lineText[charIndex];
|
||||||
setTimeout(typewriter, 60);
|
charIndex++;
|
||||||
|
const t = setTimeout(typeChar, 60);
|
||||||
|
scene1Timeouts.push(t);
|
||||||
} else {
|
} else {
|
||||||
currentLine++;
|
scene1LineIndex++;
|
||||||
currentChar = 0;
|
const t = setTimeout(typewriter, 500);
|
||||||
setTimeout(typewriter, 500);
|
scene1Timeouts.push(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
typeChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
function skipScene1() {
|
||||||
|
// Clear all pending timeouts
|
||||||
|
scene1Timeouts.forEach(t => clearTimeout(t));
|
||||||
|
scene1Timeouts = [];
|
||||||
|
// Show all text instantly
|
||||||
|
document.getElementById('line1').textContent = scene1lines[0];
|
||||||
|
document.getElementById('line2').textContent = scene1lines[1];
|
||||||
|
document.getElementById('line3').textContent = scene1lines[2];
|
||||||
|
document.getElementById('line1').style.visibility = 'visible';
|
||||||
|
document.getElementById('line2').style.visibility = 'visible';
|
||||||
|
document.getElementById('line3').style.visibility = 'visible';
|
||||||
|
showButton();
|
||||||
|
}
|
||||||
|
|
||||||
// Show "FOLLOW THEM" button
|
// Show "FOLLOW THEM" button
|
||||||
function showButton() {
|
function showButton() {
|
||||||
@@ -276,28 +401,154 @@
|
|||||||
}, 30);
|
}, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Placeholder for Scene 2 (to be expanded later)
|
// Scene 2 loader with blinking cursor (5 blinks), and text
|
||||||
function loadScene2(sceneElem) {
|
function loadScene2(sceneElem) {
|
||||||
sceneElem.innerHTML = '<p>The signal grows stronger. The path reveals itself...</p>';
|
|
||||||
sceneElem.style.display = 'flex';
|
sceneElem.style.display = 'flex';
|
||||||
|
const cursor = document.getElementById('blinkCursor');
|
||||||
|
const textContainer = document.getElementById('scene2Text');
|
||||||
|
const learnBtn = document.getElementById('learnBtn');
|
||||||
|
|
||||||
let opacity = 0;
|
let opacity = 0;
|
||||||
const fadeIn = setInterval(() => {
|
const fadeIn = setInterval(() => {
|
||||||
opacity += 0.05;
|
opacity += 0.05;
|
||||||
if (opacity >= 1) {
|
if (opacity >= 1) {
|
||||||
opacity = 1;
|
opacity = 1;
|
||||||
clearInterval(fadeIn);
|
clearInterval(fadeIn);
|
||||||
|
|
||||||
|
// Show blinking cursor - blink 5 times (5 seconds)
|
||||||
|
cursor.style.display = 'block';
|
||||||
|
cursor.style.opacity = '1';
|
||||||
|
let blinkCount = 0;
|
||||||
|
let isVisible = true;
|
||||||
|
const blinkInterval = setInterval(() => {
|
||||||
|
isVisible = !isVisible;
|
||||||
|
cursor.style.opacity = isVisible ? '1' : '0';
|
||||||
|
blinkCount++;
|
||||||
|
if (blinkCount >= 10) { // 5 complete cycles (on+off = 2 toggles per cycle)
|
||||||
|
clearInterval(blinkInterval);
|
||||||
|
cursor.style.display = 'none';
|
||||||
|
|
||||||
|
// Type the new pre-LEARN text - starts calm, accelerates to normal reading speed
|
||||||
|
typewriterLines(
|
||||||
|
[
|
||||||
|
"...AND THAT AWARENESS ISN'T JUST COINCIDENCE. YOU'RE SITTING IN FRONT OF THIS SCREEN AT THIS EXACT MOMENT IN TIME FOR A REASON.",
|
||||||
|
".....COULD THAT REASON BE THAT YOU NEED TO LEARN SOMETHING?"
|
||||||
|
],
|
||||||
|
textContainer,
|
||||||
|
() => {
|
||||||
|
// Show "LEARN" button
|
||||||
|
learnBtn.style.visibility = 'visible';
|
||||||
|
let btnOpacity = 0;
|
||||||
|
const btnFadeIn = setInterval(() => {
|
||||||
|
btnOpacity += 0.05;
|
||||||
|
if (btnOpacity >= 1) {
|
||||||
|
btnOpacity = 1;
|
||||||
|
clearInterval(btnFadeIn);
|
||||||
|
learnBtn.style.pointerEvents = 'auto';
|
||||||
|
}
|
||||||
|
learnBtn.style.opacity = btnOpacity;
|
||||||
|
}, 30);
|
||||||
|
},
|
||||||
|
120, // Start calm (120ms/char)
|
||||||
|
800, // Calm line delay
|
||||||
|
60 // Accelerate to normal reading speed (60ms/char)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, 500); // 500ms on, 500ms off = 1 second per blink
|
||||||
}
|
}
|
||||||
sceneElem.style.opacity = opacity;
|
sceneElem.style.opacity = opacity;
|
||||||
}, 30);
|
}, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "LEARN" button click handler
|
||||||
|
function handleLearnClick() {
|
||||||
|
const learnBtn = document.getElementById('learnBtn');
|
||||||
|
const textContainer = document.getElementById('scene2Text');
|
||||||
|
|
||||||
|
learnBtn.style.pointerEvents = 'none';
|
||||||
|
learnBtn.style.opacity = 0;
|
||||||
|
learnBtn.style.visibility = 'hidden';
|
||||||
|
|
||||||
|
// Clear previous text to prevent appending
|
||||||
|
textContainer.textContent = '';
|
||||||
|
|
||||||
|
typewriterLines(
|
||||||
|
[
|
||||||
|
"THE SIGNAL IS NOW RECEIVING.",
|
||||||
|
"PREPARE FOR THE NEXT TRANSMISSION."
|
||||||
|
],
|
||||||
|
textContainer,
|
||||||
|
() => {
|
||||||
|
// Placeholder for Scene 3
|
||||||
|
},
|
||||||
|
30, // Fast char delay for anxious rhythm
|
||||||
|
200 // Fast line delay for anxious rhythm
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize on load
|
// Initialize on load
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
setTimeout(crtFlicker, 1500);
|
setTimeout(crtFlicker, 1500);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Button click handler
|
// Button click handlers
|
||||||
document.getElementById('followBtn').addEventListener('click', transitionToScene2);
|
document.getElementById('followBtn').addEventListener('click', transitionToScene2);
|
||||||
|
document.getElementById('learnBtn').addEventListener('click', handleLearnClick);
|
||||||
|
|
||||||
|
// Keyboard shortcuts for testing
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
// Escape alone: Skip current animation to text
|
||||||
|
|
||||||
|
// Scene 1 skip (rain or typewriter)
|
||||||
|
const textContainer = document.getElementById('textContainer');
|
||||||
|
const canvas = document.getElementById('matrixCanvas');
|
||||||
|
if (textContainer.style.visibility !== 'visible') {
|
||||||
|
// Skip rain, show Scene 1 text instantly
|
||||||
|
canvas.style.opacity = '0.15';
|
||||||
|
skipScene1();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scene 2 pre-LEARN skip (cursor blinking)
|
||||||
|
const scene2Text = document.getElementById('scene2Text');
|
||||||
|
const learnBtn = document.getElementById('learnBtn');
|
||||||
|
const cursor = document.getElementById('blinkCursor');
|
||||||
|
if (cursor.style.display === 'block') {
|
||||||
|
// Skip cursor, show pre-LEARN text + LEARN button
|
||||||
|
cursor.style.display = 'none';
|
||||||
|
scene2Text.textContent = "...AND THAT AWARENESS ISN'T JUST COINCIDENCE. YOU'RE SITTING IN FRONT OF THIS SCREEN AT THIS EXACT MOMENT IN TIME FOR A REASON.";
|
||||||
|
scene2Text.style.visibility = 'visible';
|
||||||
|
learnBtn.style.visibility = 'visible';
|
||||||
|
learnBtn.style.opacity = '1';
|
||||||
|
learnBtn.style.pointerEvents = 'auto';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.key === 'Backspace') {
|
||||||
|
e.preventDefault(); // Prevent browser back navigation
|
||||||
|
|
||||||
|
// Fast-forward to last scene (Scene 2 post-LEARN)
|
||||||
|
// Hide Scene 1 elements
|
||||||
|
document.getElementById('matrixCanvas').style.display = 'none';
|
||||||
|
document.getElementById('textContainer').style.display = 'none';
|
||||||
|
document.getElementById('followBtn').style.display = 'none';
|
||||||
|
|
||||||
|
// Show Scene 2 with post-LEARN text
|
||||||
|
const scene2 = document.getElementById('scene2');
|
||||||
|
const textContainer = document.getElementById('scene2Text');
|
||||||
|
const learnBtn = document.getElementById('learnBtn');
|
||||||
|
const cursor = document.getElementById('blinkCursor');
|
||||||
|
|
||||||
|
scene2.style.display = 'flex';
|
||||||
|
scene2.style.opacity = '1';
|
||||||
|
cursor.style.display = 'none';
|
||||||
|
learnBtn.style.display = 'none';
|
||||||
|
|
||||||
|
// Show post-LEARN text instantly
|
||||||
|
textContainer.textContent = "THE SIGNAL IS NOW RECEIVING. PREPARE FOR THE NEXT TRANSMISSION.";
|
||||||
|
textContainer.style.visibility = 'visible';
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user