glitchcraft/app/app.js

410 lines
11 KiB
JavaScript
Raw Normal View History

/**
* Main application logic for GlitchCraft
* Handles UI interactions and PWA registration
*/
/* global ZalgoGenerator */
// Initialize zalgo generator
const zalgo = new ZalgoGenerator();
// DOM elements
const inputText = document.getElementById('inputText');
const outputText = document.getElementById('outputText');
const intensitySlider = document.getElementById('intensity');
const intensityValue = document.getElementById('intensityValue');
const zalgoModeSelect = document.getElementById('zalgoMode');
const clearBtn = document.getElementById('clearBtn');
const copyNotification = document.getElementById('copyNotification');
// Easter egg state
let titleClickCount = 0;
let titleClickTimer = null;
let isWitchingHour = false;
let lastShakeTime = 0;
/**
* Update the corrupted text output
*/
function updateOutput() {
const text = inputText.value;
let intensity = parseInt(intensitySlider.value);
let mode = zalgoModeSelect.value;
// Easter egg checks
const easterEggTriggered = checkEasterEggs(text);
// If easter egg was triggered, don't do normal generation
if (easterEggTriggered) {
return;
}
// Apply witching hour effect
if (isWitchingHour) {
intensity = Math.max(intensity, 8);
mode = 'heavy';
}
if (text) {
outputText.value = zalgo.generate(text, intensity, mode);
} else {
outputText.value = '';
}
}
/**
* Check for easter eggs in the input text
*/
function checkEasterEggs(text) {
const lowerText = text.toLowerCase().trim();
// "He Comes" Mode
if (lowerText === 'he comes' || lowerText === 'zalgo') {
triggerHeComes();
return true;
}
// 404 Text Not Found
if (lowerText === '404') {
trigger404();
return true;
}
// Matrix Mode
if (lowerText === 'red pill') {
triggerMatrixRed();
return true;
}
if (lowerText === 'blue pill') {
triggerMatrixBlue();
return true;
}
// Credits
if (lowerText === 'credits') {
triggerCredits();
return true;
}
return false;
}
/**
* Copy text to clipboard and show notification
*/
async function copyToClipboard() {
if (!outputText.value) return;
try {
await navigator.clipboard.writeText(outputText.value);
// Show copy notification
copyNotification.classList.add('show');
setTimeout(() => {
copyNotification.classList.remove('show');
}, 2000);
} catch (err) {
// Fallback for older browsers
outputText.select();
document.execCommand('copy');
// Show copy notification
copyNotification.classList.add('show');
setTimeout(() => {
copyNotification.classList.remove('show');
}, 2000);
}
}
/**
* Clear all text fields
*/
function clearAll() {
inputText.value = '';
outputText.value = '';
inputText.focus();
}
/**
* Easter Egg Functions
*/
// "He Comes" Mode
function triggerHeComes() {
zalgoModeSelect.value = 'heavy';
intensitySlider.value = 10;
intensityValue.textContent = '10';
// Flash effect
document.body.style.backgroundColor = '#330000';
setTimeout(() => {
document.body.style.backgroundColor = '';
}, 200);
// Update output after mode change
setTimeout(() => {
outputText.value = zalgo.generate(inputText.value, 10, 'heavy');
}, 100);
}
// 404 Text Not Found
function trigger404() {
outputText.value = 'T̷̢̧e̴̢̧x̷̰t̸̨̧ ̷̢̧n̴̢̧o̷̰t̸̨̧ ̷̢̧f̴̢̧o̷̰ų̸̧n̷̢̧d̴̢̧';
// Override copy notification
window.tempCopyFunction = async function () {
await navigator.clipboard.writeText(outputText.value);
copyNotification.textContent = 'Error copied successfully!';
copyNotification.classList.add('show');
setTimeout(() => {
copyNotification.classList.remove('show');
copyNotification.textContent = 'Copied!';
}, 3000);
};
// Restore original after 10 seconds
setTimeout(() => {
window.tempCopyFunction = null;
}, 10000);
}
// Matrix Red Pill
function triggerMatrixRed() {
zalgoModeSelect.value = 'heavy';
intensitySlider.value = 9;
intensityValue.textContent = '9';
// Red tint effect
document.documentElement.style.filter = 'hue-rotate(0deg) saturate(150%) brightness(90%)';
document.documentElement.style.background =
'linear-gradient(rgba(255,0,0,0.1), rgba(255,0,0,0.05))';
outputText.value = zalgo.generate('Welcome to the real world', 9, 'heavy');
// Clear effect after 5 seconds
setTimeout(() => {
document.documentElement.style.filter = '';
document.documentElement.style.background = '';
}, 5000);
}
// Matrix Blue Pill
function triggerMatrixBlue() {
zalgoModeSelect.value = 'mini';
intensitySlider.value = 1;
intensityValue.textContent = '1';
// Blue calm effect
document.documentElement.style.filter = 'hue-rotate(240deg) saturate(120%) brightness(110%)';
outputText.value = 'You chose... wisely';
setTimeout(() => {
document.documentElement.style.filter = '';
outputText.value = zalgo.generate('Back to the ordinary world', 1, 'mini');
}, 3000);
}
// Developer Credits
function triggerCredits() {
const credits = 'Made with ❤️ and chaos by Ole-Morten Duesund';
outputText.value = zalgo.generate(credits, 7, 'full');
}
// Title Click Counter for Credits
function handleTitleClick() {
titleClickCount++;
if (titleClickTimer) {
clearTimeout(titleClickTimer);
}
if (titleClickCount >= 10) {
triggerCredits();
titleClickCount = 0;
return;
}
// Reset counter after 3 seconds
titleClickTimer = setTimeout(() => {
titleClickCount = 0;
}, 3000);
}
// Witching Hour Check (3:33 AM)
function checkWitchingHour() {
const now = new Date();
const hour = now.getHours();
const minute = now.getMinutes();
const isCurrentlyWitchingHour = hour === 3 && minute === 33;
if (isCurrentlyWitchingHour && !isWitchingHour) {
isWitchingHour = true;
// Dark theme effect
document.documentElement.style.filter = 'brightness(70%) contrast(120%)';
document.body.style.animation = 'subtle-shake 0.1s infinite';
// Show message
const originalSubtitle = document.querySelector('.subtitle').textContent;
document.querySelector('.subtitle').textContent = 'T̷̢̧h̴̢̧ḛ̷ ̸̨̧w̷̢̧i̴̢̧t̷̰c̸̨̧h̷̢̧i̴̢̧n̷̰g̸̨̧ ̷̢̧h̴̢̧o̷̰ų̸̧r̷̢̧';
// Restore after 1 minute
setTimeout(() => {
isWitchingHour = false;
document.documentElement.style.filter = '';
document.body.style.animation = '';
document.querySelector('.subtitle').textContent = originalSubtitle;
}, 60000);
} else if (!isCurrentlyWitchingHour && isWitchingHour) {
isWitchingHour = false;
document.documentElement.style.filter = '';
document.body.style.animation = '';
}
}
// Mobile Shake Detection
function handleDeviceMotion(event) {
const acceleration = event.accelerationIncludingGravity;
if (!acceleration) return;
// Throttle shake detection to prevent spam
const now = Date.now();
if (now - lastShakeTime < 1000) return;
const shake = Math.abs(acceleration.x) + Math.abs(acceleration.y) + Math.abs(acceleration.z);
if (shake > 30) {
lastShakeTime = now;
// Random mode and intensity
const modes = ['full', 'above', 'below', 'middle', 'mini', 'heavy'];
const randomMode = modes[Math.floor(Math.random() * modes.length)];
const randomIntensity = Math.floor(Math.random() * 10) + 1;
zalgoModeSelect.value = randomMode;
intensitySlider.value = randomIntensity;
intensityValue.textContent = randomIntensity;
// Haptic feedback if available
if (navigator.vibrate) {
navigator.vibrate(100);
}
// Visual feedback
copyNotification.textContent = 'S̷̢̧h̴̢̧a̷̰k̸̨̧e̷̢̧n̴̢̧,̷̰ ̸̨̧n̷̢̧o̴̢̧t̷̰ ̸̨̧s̷̢̧t̴̢̧ḭ̷r̸̨̧r̷̢̧e̴̢̧d̷̰';
copyNotification.classList.add('show');
setTimeout(() => {
copyNotification.classList.remove('show');
copyNotification.textContent = 'Copied!';
}, 2000);
updateOutput();
}
}
// Event listeners
inputText.addEventListener('input', updateOutput);
intensitySlider.addEventListener('input', () => {
intensityValue.textContent = intensitySlider.value;
updateOutput();
});
zalgoModeSelect.addEventListener('change', updateOutput);
outputText.addEventListener('click', () => {
// Check for custom copy function (404 easter egg)
if (window.tempCopyFunction) {
window.tempCopyFunction();
} else {
copyToClipboard();
}
});
clearBtn.addEventListener('click', clearAll);
// Handle keyboard shortcuts
document.addEventListener('keydown', e => {
// Ctrl/Cmd + K to clear
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
e.preventDefault();
clearAll();
}
// Ctrl/Cmd + C when output is focused to copy
if ((e.ctrlKey || e.metaKey) && e.key === 'c' && document.activeElement === outputText) {
copyToClipboard();
}
});
// Register service worker for PWA functionality
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('sw.js')
.then(registration => {
console.log('Service Worker registered successfully:', registration.scope);
})
.catch(error => {
console.log('Service Worker registration failed:', error);
});
});
}
// Handle install prompt for PWA
window.addEventListener('beforeinstallprompt', e => {
// Prevent the mini-infobar from appearing on mobile
e.preventDefault();
// Store the event so it can be triggered later if needed
// Currently not used but kept for potential future install button
window.deferredPrompt = e;
console.log('Install prompt ready');
});
// Focus input on load
window.addEventListener('load', () => {
inputText.focus();
// Set up easter egg event listeners
setupEasterEggs();
});
// Easter Egg Setup
function setupEasterEggs() {
// Title click for credits
const title = document.querySelector('h1');
title.addEventListener('click', handleTitleClick);
title.style.cursor = 'pointer';
// Witching hour check every minute
setInterval(checkWitchingHour, 60000);
checkWitchingHour(); // Initial check
// Mobile shake detection
if (window.DeviceMotionEvent) {
window.addEventListener('devicemotion', handleDeviceMotion);
}
// Request device motion permission on iOS 13+
if (typeof DeviceMotionEvent.requestPermission === 'function') {
// We'll request permission on first user interaction
document.addEventListener('touchstart', requestMotionPermission, { once: true });
}
}
// Request motion permission for iOS
function requestMotionPermission() {
if (typeof DeviceMotionEvent.requestPermission === 'function') {
DeviceMotionEvent.requestPermission()
.then(permissionState => {
if (permissionState === 'granted') {
window.addEventListener('devicemotion', handleDeviceMotion);
}
})
.catch(console.error);
}
}