init
This commit is contained in:
278
public/main.js
Normal file
278
public/main.js
Normal file
@@ -0,0 +1,278 @@
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
POULINKES.COM — Sacred Chicken Interaction Engine v1.0.0
|
||||
Warning: This file is watched by the Poulinkes.
|
||||
They know what you are.
|
||||
═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// ─── FEATHER RAIN ────────────────────────────────────────────
|
||||
const FEATHERS = ['🪶', '🪶', '🪶', '✨', '🥚'];
|
||||
let featherInterval = null;
|
||||
|
||||
function spawnFeather() {
|
||||
const el = document.createElement('div');
|
||||
el.classList.add('feather');
|
||||
el.textContent = FEATHERS[Math.floor(Math.random() * FEATHERS.length)];
|
||||
el.style.left = Math.random() * 100 + 'vw';
|
||||
el.style.animationDuration = (6 + Math.random() * 8) + 's';
|
||||
el.style.fontSize = (0.8 + Math.random() * 1.2) + 'rem';
|
||||
document.body.appendChild(el);
|
||||
el.addEventListener('animationend', () => el.remove());
|
||||
}
|
||||
|
||||
function startFeathers() {
|
||||
spawnFeather();
|
||||
featherInterval = setInterval(() => {
|
||||
if (Math.random() < 0.7) spawnFeather();
|
||||
}, 2200);
|
||||
}
|
||||
|
||||
// ─── CLUCK SOUND (Web Audio API) ─────────────────────────────
|
||||
function playCluck() {
|
||||
try {
|
||||
const ctx = new (window.AudioContext || window.webkitAudioContext)();
|
||||
|
||||
const times = [0, 0.07, 0.14];
|
||||
times.forEach((t) => {
|
||||
const osc = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
const dist = ctx.createWaveShaper();
|
||||
|
||||
// Distortion curve for that raw chicken rasp
|
||||
const curve = new Float32Array(256);
|
||||
for (let i = 0; i < 256; i++) {
|
||||
const x = (i * 2) / 256 - 1;
|
||||
curve[i] = ((Math.PI + 200) * x) / (Math.PI + 200 * Math.abs(x));
|
||||
}
|
||||
dist.curve = curve;
|
||||
|
||||
osc.connect(dist);
|
||||
dist.connect(gain);
|
||||
gain.connect(ctx.destination);
|
||||
|
||||
osc.type = 'sawtooth';
|
||||
osc.frequency.setValueAtTime(700 - t * 500, ctx.currentTime + t);
|
||||
osc.frequency.exponentialRampToValueAtTime(120, ctx.currentTime + t + 0.12);
|
||||
|
||||
gain.gain.setValueAtTime(0, ctx.currentTime + t);
|
||||
gain.gain.linearRampToValueAtTime(0.25, ctx.currentTime + t + 0.01);
|
||||
gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + t + 0.13);
|
||||
|
||||
osc.start(ctx.currentTime + t);
|
||||
osc.stop(ctx.currentTime + t + 0.14);
|
||||
});
|
||||
|
||||
// Close context after last note
|
||||
setTimeout(() => ctx.close(), 600);
|
||||
} catch (e) {
|
||||
// Even in failure, the poulinkes forgive you
|
||||
}
|
||||
}
|
||||
|
||||
// ─── CLUCK BUTTON ────────────────────────────────────────────
|
||||
function initCluckButton() {
|
||||
const btn = document.getElementById('cluck-btn');
|
||||
if (!btn) return;
|
||||
btn.addEventListener('click', () => {
|
||||
playCluck();
|
||||
btn.classList.add('clucking');
|
||||
btn.textContent = '🐔 B'CLUCK! 🐔';
|
||||
setTimeout(() => {
|
||||
btn.classList.remove('clucking');
|
||||
btn.textContent = '🐔 TRIGGER THE CLUCK 🐔';
|
||||
}, 800);
|
||||
});
|
||||
}
|
||||
|
||||
// ─── TOAST MESSAGE ────────────────────────────────────────────
|
||||
function showToast(msg, duration = 4000) {
|
||||
let toast = document.getElementById('cluck-toast');
|
||||
if (!toast) {
|
||||
toast = document.createElement('div');
|
||||
toast.id = 'cluck-toast';
|
||||
document.body.appendChild(toast);
|
||||
}
|
||||
toast.innerHTML = msg;
|
||||
toast.classList.add('show');
|
||||
clearTimeout(toast._timer);
|
||||
toast._timer = setTimeout(() => toast.classList.remove('show'), duration);
|
||||
}
|
||||
|
||||
// ─── CLUCK KEYBOARD DETECTOR ──────────────────────────────────
|
||||
let cluckBuffer = '';
|
||||
const CLUCK_MESSAGES = [
|
||||
'🥚 <strong>YOU KNOW THE WORD.</strong><br><small>They are already watching.</small>',
|
||||
'🐔 The poulinkes acknowledge your presence.<br><small>They have always known.</small>',
|
||||
'🪶 Interesting that you knew this word.<br><small>Almost as if... you were one of them.</small>',
|
||||
'🥚 C-L-U-C-K.<br><small>The ancient greeting. You remembered.</small>',
|
||||
'🐔 <strong>CLUCK ACCEPTED.</strong><br><small>Your DNA has been logged.</small>',
|
||||
];
|
||||
let cluckMsgIndex = 0;
|
||||
|
||||
function initCluckDetector() {
|
||||
document.addEventListener('keydown', (e) => {
|
||||
cluckBuffer += e.key.toLowerCase();
|
||||
if (cluckBuffer.length > 8) cluckBuffer = cluckBuffer.slice(-8);
|
||||
|
||||
if (cluckBuffer.includes('cluck')) {
|
||||
cluckBuffer = '';
|
||||
playCluck();
|
||||
setTimeout(playCluck, 200);
|
||||
showToast(CLUCK_MESSAGES[cluckMsgIndex % CLUCK_MESSAGES.length], 5000);
|
||||
cluckMsgIndex++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ─── KONAMI CODE → CHICKEN OVERLORD MODE ─────────────────────
|
||||
const KONAMI = [
|
||||
'ArrowUp','ArrowUp','ArrowDown','ArrowDown',
|
||||
'ArrowLeft','ArrowRight','ArrowLeft','ArrowRight',
|
||||
'b','a'
|
||||
];
|
||||
let konamiIndex = 0;
|
||||
|
||||
function initKonami() {
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === KONAMI[konamiIndex]) {
|
||||
konamiIndex++;
|
||||
if (konamiIndex === KONAMI.length) {
|
||||
konamiIndex = 0;
|
||||
activateOverlordMode();
|
||||
}
|
||||
} else {
|
||||
konamiIndex = e.key === KONAMI[0] ? 1 : 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function activateOverlordMode() {
|
||||
let overlay = document.getElementById('overlord-overlay');
|
||||
if (!overlay) {
|
||||
overlay = document.createElement('div');
|
||||
overlay.id = 'overlord-overlay';
|
||||
overlay.innerHTML = `
|
||||
<div class="overlord-chicken">🐔</div>
|
||||
<div class="overlord-text">CHICKEN OVERLORD MODE</div>
|
||||
<div class="overlord-sub">
|
||||
You have awakened the Ancient Protocol.<br>
|
||||
The poulinkes did not give you this code.<br>
|
||||
<em>You always had it. Think about that.</em><br><br>
|
||||
The eggs are watching. They have always been watching.
|
||||
</div>
|
||||
<button class="overlord-close" onclick="document.getElementById('overlord-overlay').classList.remove('active')">
|
||||
[ I SUBMIT TO THE FLOCK ]
|
||||
</button>
|
||||
`;
|
||||
document.body.appendChild(overlay);
|
||||
}
|
||||
overlay.classList.add('active');
|
||||
|
||||
// Sound assault
|
||||
for (let i = 0; i < 5; i++) {
|
||||
setTimeout(playCluck, i * 120);
|
||||
}
|
||||
|
||||
// Feather burst
|
||||
for (let i = 0; i < 20; i++) {
|
||||
setTimeout(spawnFeather, i * 80);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── EGG PERSPECTIVE (random flip) ───────────────────────────
|
||||
function initEggPerspective() {
|
||||
// 12% chance on load after 4s
|
||||
setTimeout(() => {
|
||||
if (Math.random() < 0.12) triggerEggPerspective();
|
||||
}, 4000);
|
||||
|
||||
// Periodic check every 45s
|
||||
setInterval(() => {
|
||||
if (Math.random() < 0.05) triggerEggPerspective();
|
||||
}, 45000);
|
||||
}
|
||||
|
||||
function triggerEggPerspective() {
|
||||
if (document.body.classList.contains('egg-perspective')) return;
|
||||
showToast('🥚 <strong>EGG PERSPECTIVE ACTIVATED</strong><br><small>This is how they see us.</small>', 3000);
|
||||
document.body.classList.add('egg-perspective');
|
||||
setTimeout(() => document.body.classList.remove('egg-perspective'), 2600);
|
||||
}
|
||||
|
||||
// ─── JOIN FORM ────────────────────────────────────────────────
|
||||
function initJoinForm() {
|
||||
const form = document.getElementById('join-form');
|
||||
if (!form) return;
|
||||
|
||||
form.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const container = document.getElementById('join-form-container');
|
||||
const success = document.getElementById('join-success');
|
||||
|
||||
if (container) container.style.display = 'none';
|
||||
if (success) success.style.display = 'block';
|
||||
|
||||
// Celebration
|
||||
for (let i = 0; i < 15; i++) setTimeout(spawnFeather, i * 100);
|
||||
for (let i = 0; i < 3; i++) setTimeout(playCluck, i * 200);
|
||||
});
|
||||
}
|
||||
|
||||
// ─── STAT BAR WIDTHS ─────────────────────────────────────────
|
||||
function initStatBars() {
|
||||
document.querySelectorAll('.stat-fill[data-value]').forEach(bar => {
|
||||
const val = parseInt(bar.dataset.value, 10);
|
||||
bar.style.width = val + '%';
|
||||
});
|
||||
}
|
||||
|
||||
// ─── CONSPIRACY CARD ROTATIONS ────────────────────────────────
|
||||
function initConspiracyRotations() {
|
||||
document.querySelectorAll('.conspiracy-article').forEach(article => {
|
||||
const rot = (Math.random() * 6 - 3).toFixed(1);
|
||||
article.style.setProperty('--rot', rot + 'deg');
|
||||
});
|
||||
}
|
||||
|
||||
// ─── ARE YOU A POULINKE? (subtle hint on scroll) ──────────────
|
||||
let hintShown = false;
|
||||
function initPoulinkeHint() {
|
||||
window.addEventListener('scroll', () => {
|
||||
if (hintShown) return;
|
||||
const scrolled = window.scrollY / (document.body.scrollHeight - window.innerHeight);
|
||||
if (scrolled > 0.75) {
|
||||
hintShown = true;
|
||||
setTimeout(() => {
|
||||
showToast(
|
||||
'🪶 <strong>A THOUGHT.</strong><br><small>Why do you feel so at home here?</small>',
|
||||
6000
|
||||
);
|
||||
}, 1500);
|
||||
}
|
||||
}, { passive: true });
|
||||
}
|
||||
|
||||
// ─── INIT ALL ─────────────────────────────────────────────────
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
startFeathers();
|
||||
initCluckButton();
|
||||
initCluckDetector();
|
||||
initKonami();
|
||||
initEggPerspective();
|
||||
initJoinForm();
|
||||
initStatBars();
|
||||
initConspiracyRotations();
|
||||
initPoulinkeHint();
|
||||
|
||||
// Secret: right-clicking a chicken emoji shows a message
|
||||
document.querySelectorAll('[data-secret-chicken]').forEach(el => {
|
||||
el.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault();
|
||||
showToast('🐔 <strong>DO NOT STARE INTO THE POULINKE.</strong><br><small>It is already too late.</small>', 5000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user