Files
Hello-World/index.html
2025-08-24 19:28:40 +01:00

201 lines
8.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Boot Sequence — Wake up, Neo</title>
<style>
:root { --bg:#000; --green:#33ff66; }
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
margin: 0; background: var(--bg); color: var(--green);
font: 16px/1.5 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
#viewport { position: fixed; inset: 0; padding: 24px 16px; }
#screen { width:100%; height:100%; overflow:auto; white-space:pre-wrap;
text-shadow: 0 0 10px rgba(51,255,102,.4), 0 0 20px rgba(51,255,102,.2), 0 0 2px rgba(51,255,102,.6);
}
/* CRT scanlines + bloom */
body.crt::before, body.crt::after { content:""; position: fixed; left:0; right:0; pointer-events:none; }
body.crt::before { top:0; bottom:0; background: linear-gradient(rgba(0,0,0,0) 50%, rgba(0,255,120,0.05) 50%); background-size:100% 4px; mix-blend-mode: overlay; }
body.crt::after { top:-2px; bottom:-2px; background: radial-gradient(circle at 50% 20%, rgba(0,255,153,0.12), rgba(0,0,0,0) 35%), linear-gradient(to bottom, rgba(255,255,255,0.02), rgba(0,0,0,0) 30%, rgba(0,0,0,0) 70%, rgba(255,255,255,0.02)); }
/* Subtle global flicker */
body.crt { animation: crt-flicker 8s infinite steps(1); }
@keyframes crt-flicker {
0%,100% { filter:none; }
2% { filter: brightness(1.2) contrast(1.05) saturate(1.1); }
4% { filter: brightness(.9) contrast(1.1); }
6% { filter: brightness(1.1); }
}
/* Quick glitch class toggled by JS */
.glitch { animation: glitch-burst .18s steps(1) 2; }
@keyframes glitch-burst {
0% { transform: translateY(0); filter: contrast(1.2) brightness(1.2); }
50% { transform: translateY(1px); filter: contrast(1.5) brightness(0.8); }
100% { transform: translateY(0); filter:none; }
}
.cursor { display:inline-block; width:.7ch; height:1.05em; vertical-align:-0.15em; margin-left:2px; background: currentColor; animation: blink 1s steps(1) infinite; }
.cursor.flash { animation: blink-fast .3s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }
@keyframes blink-fast { 50% { opacity: 0; } }
.help { position: fixed; bottom: 10px; right: 12px; font-size: 12px; opacity:.6 }
.muted { opacity: .4 }
kbd { border:1px solid currentColor; padding:1px 4px; border-radius:3px; font-size:.9em }
a { color: inherit; }
</style>
</head>
<body class="crt">
<div id="viewport">
<div id="screen" role="log" aria-live="polite" aria-atomic="false"></div>
</div>
<div class="help">Click or press <kbd>Space</kbd> to fastforward · Press <kbd>M</kbd> to toggle sound</div>
<script>
(() => {
const screen = document.getElementById('screen');
/* ---------------- WebAudio: tiny synth ---------------- */
const AudioCtx = window.AudioContext || window.webkitAudioContext;
let ctx = null; // created on first user gesture
let soundOn = true;
function ensureAudio() {
if (!ctx) ctx = new AudioCtx();
if (ctx.state === 'suspended') ctx.resume();
}
function tone({freq=440, type='square', dur=0.03, vol=0.02}){
if (!soundOn || !ctx) return;
const t0 = ctx.currentTime;
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = type; osc.frequency.value = freq;
gain.gain.setValueAtTime(0, t0);
gain.gain.linearRampToValueAtTime(vol, t0 + 0.002);
gain.gain.exponentialRampToValueAtTime(0.0005, t0 + Math.max(0.01, dur));
osc.connect(gain).connect(ctx.destination);
osc.start(t0); osc.stop(t0 + dur + 0.02);
}
function noise({dur=0.12, vol=0.02}){
if (!soundOn || !ctx) return;
const bufferSize = Math.floor(ctx.sampleRate * dur);
const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
const data = buffer.getChannelData(0);
for (let i=0; i<bufferSize; i++) data[i] = (Math.random()*2-1) * 0.8;
const src = ctx.createBufferSource();
const gain = ctx.createGain();
gain.gain.value = vol;
src.buffer = buffer;
src.connect(gain).connect(ctx.destination);
src.start();
}
function typeClick(){ if (Math.random() < 0.6) tone({freq:120+Math.random()*120, dur:0.015, vol:0.015}); }
function okBeep(){ tone({freq:880, dur:0.04, vol:0.03}); }
function warnBuzz(){ noise({dur:0.18, vol:0.03}); tone({freq:140, type:'sawtooth', dur:0.08, vol:0.02}); }
function bootChirp(){ tone({freq:440, dur:0.06, vol:0.03}); tone({freq:660, dur:0.06, vol:0.03}); }
function finale(){ [392,523,784].forEach((f,i)=> setTimeout(()=> tone({freq:f, dur:0.08, vol:0.03}), i*90)); }
/* ---------------- Visuals & content ---------------- */
const bootLines = [
'Phoenix BIOS v4.0 Release 6.0',
'Copyright (C) 1985-2025 Phoenix Technologies Ltd.',
'CPU: ZION-9 3.60GHz (4 CPUs) ~3.6GHz',
'Memory Test: 65536K OK',
'Detecting IDE Drives ...',
'Primary Master: ST3250820AS 250GB',
'Primary Slave : TSSTcorp CDDVDW SH-222',
'S.M.A.R.T. Status: OK',
'Initializing USB Controllers ... Done.',
'Enabling Shadow RAM ... Done.',
'Booting from device: /dev/ttyS0',
'',
'Loading kernel v0.1.37 ....................... OK',
'Mounting / (ext4) read-only .................. OK',
'Starting init ',
'[ OK ] Started udev kernel device manager.',
'[ OK ] Reached target Local File Systems.',
'[ OK ] Reached target Network (online).',
'[ OK ] Started OpenSSH Daemon.',
'[ OK ] Started Matrix Link.',
'[WARN] entropy pool low, seeding...',
'[ OK ] Decrypting payload...',
'',
];
function randomHex(len=32){ return [...crypto.getRandomValues(new Uint8Array(len/2))].map(b=>b.toString(16).padStart(2,'0')).join(''); }
const noiseLines = Array.from({length:20}, () => `0x${randomHex(16)} ${randomHex(32)} ${randomHex(8)}`);
const lines = [...bootLines, ...noiseLines, '', '>>> establishing link…', ''];
let speed = 1; // 1 = normal, 3 = fast
let aborted = false;
function newline(){ screen.append(document.createElement('br')); screen.scrollTop = screen.scrollHeight; }
function append(text=''){
screen.append(document.createTextNode(text));
newline();
}
async function typeLine(line){
for (let i=0; i<line.length; i++){
if (aborted) return;
screen.append(document.createTextNode(line[i]));
typeClick();
screen.scrollTop = screen.scrollHeight;
await sleep(speed>1 ? 3 : 12 + Math.random()*30);
}
newline();
if (line.includes('[ OK ]')) okBeep();
if (line.startsWith('[WARN]')) { warnBuzz(); bodyGlitch(); }
}
function sleep(ms){ return new Promise(r => setTimeout(r, ms)); }
function bodyGlitch(){ document.body.classList.add('glitch'); setTimeout(()=> document.body.classList.remove('glitch'), 180); }
// fast-forward & sound controls
const fast = () => { speed = 3; };
document.addEventListener('click', () => { ensureAudio(); fast(); });
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') { e.preventDefault(); ensureAudio(); speed = speed===1?3:1; }
if (e.key === 'Escape') { aborted = true; }
if (e.key.toLowerCase() === 'm') { soundOn = !soundOn; document.querySelector('.help').classList.toggle('muted', !soundOn); }
});
(async function run(){
await sleep(300);
bootChirp();
for (const line of lines){
if (aborted) return;
if (Math.random() < 0.15) { append(line); await sleep(60/speed); }
else { await typeLine(line); }
if (Math.random() < 0.07) bodyGlitch();
}
await sleep(400);
// Final message
const final = 'incoming messag... Andy is a cock!';
const span = document.createElement('span');
screen.append(span);
for (let i=0; i<final.length; i++){
span.textContent += final[i];
screen.scrollTop = screen.scrollHeight;
typeClick();
await sleep(120 / speed);
}
finale();
const cursor = document.createElement('span');
cursor.className = 'cursor flash';
screen.append(cursor);
screen.scrollTop = screen.scrollHeight;
})();
})();
</script>
</body>
</html>