Save point: Desktop OS security comparison (scene7) + exfiltration scenes with real-world counter values, SOURCES references page, counter completion detection

- Scene 7: interactive canvas comparing Linux/macOS/Windows security with lock icons, animated packets
- Scene 7b: Desktop Data Exfiltration Simulator with server nodes per OS, live counter
- Real-world counter values: Android 00/yr, iOS 50/yr, macOS 00/yr, Windows 50/yr
- SOURCES button + references page (sceneRefs) with 10 citations with clickable links
- Both SOURCES and RETURN buttons appear on counter completion or via Escape skip
- Fixed JS-breaking bug: refsBackBtn element after </script> broke all event listeners
- GrapheneOS/Linux tabs show buttons immediately (no data = no wait)
This commit is contained in:
avi
2026-05-14 12:40:42 -05:00
parent 439415e748
commit 0f14b798ea

View File

@@ -302,6 +302,22 @@
.tl-year.dim::after { background: #007700; } .tl-year.dim::after { background: #007700; }
/* NEXT button */ /* NEXT button */
.btn-row {
position: fixed;
bottom: 5%;
left: 50%;
transform: translateX(-50%);
z-index: 5;
display: flex;
gap: 1rem;
justify-content: center;
align-items: center;
}
.btn-row .btnNext {
position: static;
transform: none;
margin: 0;
}
.btnNext { .btnNext {
position: fixed; position: fixed;
bottom: 5%; bottom: 5%;
@@ -724,6 +740,69 @@
} }
.exfil-legend-item { display: flex; align-items: center; gap: 0.3rem; } .exfil-legend-item { display: flex; align-items: center; gap: 0.3rem; }
.exfil-legend-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; } .exfil-legend-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
/* Scene 7 — Desktop OS interactive canvas */
#s7BtnRow, #s8BtnRow { position: fixed; bottom: 5%; left: 50%; transform: translateX(-50%); z-index: 5; display: flex; gap: 1.5rem; justify-content: center; visibility: hidden; opacity: 0; transition: opacity 0.5s ease; }
#s7BtnRow .btnNext, #s8BtnRow .btnNext { position: static; transform: none; margin: 0; visibility: visible; opacity: 1; pointer-events: auto; }
.s7canvas {
width: 100%;
max-width: 55rem;
margin-top: 0.8rem;
opacity: 0;
transition: opacity 4s ease;
}
.s7canvas.visible { opacity: 1; }
#deskCanvas {
width: 100%;
height: 320px;
border: 1px solid #003300;
border-radius: 4px;
cursor: pointer;
display: block;
}
/* Scene 7b — Desktop Exfiltration */
.s7bcanvas {
width: 100%;
max-width: 55rem;
margin-top: 0.8rem;
opacity: 0;
transition: opacity 4s ease;
}
.s7bcanvas.visible { opacity: 1; }
#exfilDeskCanvas {
width: 100%;
height: 360px;
border: 1px solid #003300;
border-radius: 4px;
cursor: pointer;
display: block;
}
/* Scene Refs — References / Citations */
#sceneRefs {
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: #000; color: #00ff00; z-index: 100;
display: flex; flex-direction: column; align-items: center; justify-content: center;
opacity: 0; pointer-events: none; transition: opacity 0.8s ease;
font-family: 'Courier New', monospace;
}
#sceneRefs.visible { opacity: 1; pointer-events: auto; }
#sceneRefs .refs-content {
width: 80%; max-width: 50rem; max-height: 80vh; overflow-y: auto;
padding: 1rem; border: 1px solid #003300; border-radius: 4px;
background: #001000;
}
#sceneRefs h2 { text-align: center; margin-bottom: 1.5rem; color: #00ff00; font-size: 1.4rem; }
#sceneRefs ol { padding-left: 1.5rem; margin: 0; }
#sceneRefs li { margin-bottom: 0.8rem; line-height: 1.5; font-size: 0.85rem; }
#sceneRefs a { color: #00cc00; text-decoration: underline; }
#sceneRefs a:hover { color: #ffff00; }
#sceneRefs .refs-back { text-align: center; margin-top: 1.5rem; }
#sceneRefs .refs-back button {
background: #003300; color: #00ff00; border: 1px solid #00ff00;
padding: 0.6rem 2rem; font-family: 'Courier New', monospace; font-size: 1rem;
cursor: pointer; border-radius: 4px;
}
#sceneRefs .refs-back button:hover { background: #005500; }
</style> </style>
</head> </head>
<body> <body>
@@ -817,11 +896,31 @@
</div> </div>
</div> </div>
<div id="scene7" class="scene"> <div id="scene7" class="scene" style="flex-direction:column;">
<div class="scene7text" id="s7Text"></div> <div class="scene7text" id="s7Text"></div>
<div class="s7visual" id="s7Visual"></div> <div class="s7canvas" id="s7Canvas">
<canvas id="deskCanvas" width="800" height="320"></canvas>
<div class="mesh-status" id="deskStatus">CLICK A TAB TO COMPARE OS SECURITY</div>
</div>
<div id="s7BtnRow">
<button class="btnNext" id="nextFromScene7">SEE THE RISK</button>
<button class="btnNext" id="returnFromScene7">RETURN</button> <button class="btnNext" id="returnFromScene7">RETURN</button>
</div> </div>
</div>
<div id="scene7b" class="scene" style="flex-direction:column;">
<div class="scene7text" id="s7bText"></div>
<div class="s7bcanvas" id="s7bCanvas">
<canvas id="exfilDeskCanvas" width="800" height="360"></canvas>
<div class="exfil-counter" id="exfilDeskCounter">DATA VALUE EXPOSED: $0/yr</div>
<div class="mesh-status" id="exfilDeskStatus">CLICK A TAB TO SEE WHERE YOUR DATA GOES</div>
<div class="exfil-legend" id="exfilDeskLegend"></div>
</div>
<div class="btn-row">
<button class="btnNext" id="sourcesFromScene7b">SOURCES</button>
<button class="btnNext" id="returnFromScene7b">RETURN</button>
</div>
</div>
<div id="scene8" class="scene" style="flex-direction:column;"> <div id="scene8" class="scene" style="flex-direction:column;">
<div class="scene8text" id="s8Text"></div> <div class="scene8text" id="s8Text"></div>
@@ -843,8 +942,11 @@
<div class="mesh-status" id="exfilStatus">CLICK A TAB TO SEE WHERE YOUR DATA GOES</div> <div class="mesh-status" id="exfilStatus">CLICK A TAB TO SEE WHERE YOUR DATA GOES</div>
<div class="exfil-legend" id="exfilLegend"></div> <div class="exfil-legend" id="exfilLegend"></div>
</div> </div>
<div class="btn-row">
<button class="btnNext" id="sourcesFromScene8b">SOURCES</button>
<button class="btnNext" id="returnFromScene8b">RETURN</button> <button class="btnNext" id="returnFromScene8b">RETURN</button>
</div> </div>
</div>
<div id="scene9" class="scene" style="flex-direction:column;"> <div id="scene9" class="scene" style="flex-direction:column;">
<div class="scene8text" id="s9Text"></div> <div class="scene8text" id="s9Text"></div>
@@ -1660,30 +1762,247 @@
},30); },30);
} }
// Desktop security interactive visualization state
let deskAnimId = null;
let deskMode = 'linux';
let deskPackets = [];
let deskClicked = false;
const deskModeData = {
linux: {
label: 'LINUX', color: '#00ff00',
locks: { kernel: true, telemetry: true, firewall: true, sandbox: false, antivirus: true, datacollection: true, updates: true },
packetType: 'stay',
status: 'LINUX GIVES YOU FULL CONTROL — NO TELEMETRY, NO RESTRICTIONS, COMPLETE TRANSPARENCY.'
},
macos: {
label: 'macOS', color: '#ffaa00',
locks: { kernel: false, telemetry: false, firewall: true, sandbox: true, antivirus: true, datacollection: false, updates: false },
packetType: 'mixed',
status: 'APPLE CONTROLS THE ECOSYSTEM — SOME PRIVACY FEATURES, BUT YOU MUST TRUST APPLE.'
},
windows: {
label: 'WINDOWS', color: '#ff4444',
locks: { kernel: false, telemetry: false, firewall: true, sandbox: false, antivirus: false, datacollection: false, updates: false },
packetType: 'leak',
status: 'MICROSOFT COLLECTS EXTENSIVE TELEMETRY — YOUR DEVICE IS NOT FULLY UNDER YOUR CONTROL.'
}
};
const deskTabs = [
{ id: 'linux', x: 170, w: 130, label: 'LINUX' },
{ id: 'macos', x: 335, w: 130, label: 'macOS' },
{ id: 'windows', x: 500, w: 130, label: 'WINDOWS' },
];
const deskFeatList = [
{ id: 'kernel', label: 'KERNEL', x: 215, y: 98, lx: 365 },
{ id: 'telemetry', label: 'TELEMETRY', x: 215, y: 131, lx: 365 },
{ id: 'firewall', label: 'FIREWALL', x: 215, y: 164, lx: 365 },
{ id: 'sandbox', label: 'SANDBOX', x: 215, y: 197, lx: 365 },
{ id: 'antivirus', label: 'ANTIVIRUS', x: 440, y: 98, lx: 570 },
{ id: 'datacollection', label: 'DATA COLL.', x: 440, y: 131, lx: 570 },
{ id: 'updates', label: 'UPDATES', x: 440, y: 164, lx: 570 },
];
function initDeskScene() {
deskClicked = false;
deskMode = 'linux';
initDeskPackets();
}
function initDeskPackets() {
const mode = deskModeData[deskMode];
deskPackets = [];
for (let i = 0; i < 4; i++) {
const orbit = mode.packetType === 'stay' || (mode.packetType === 'mixed' && i < 2);
deskPackets.push({
angle: (i / 4) * Math.PI * 2,
speed: 0.012 + Math.random() * 0.008,
radius: 30 + i * 15,
orbit: orbit,
leakX: 400 + (Math.random() - 0.5) * 200,
leakY: 30 + Math.random() * 40,
progress: Math.random(),
});
}
}
function drawDeskScene() {
const canvas = document.getElementById('deskCanvas');
if (!canvas || canvas.offsetParent === null) { deskAnimId = requestAnimationFrame(drawDeskScene); return; }
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
const mode = deskModeData[deskMode];
for (const tab of deskTabs) {
const active = tab.id === deskMode;
ctx.fillStyle = active ? mode.color : '#001100';
ctx.strokeStyle = active ? mode.color : '#003300';
ctx.lineWidth = active ? 2 : 1;
const r = 4;
ctx.beginPath();
ctx.moveTo(tab.x + r, 8);
ctx.lineTo(tab.x + tab.w - r, 8);
ctx.quadraticCurveTo(tab.x + tab.w, 8, tab.x + tab.w, 8 + r);
ctx.lineTo(tab.x + tab.w, 30 - r);
ctx.quadraticCurveTo(tab.x + tab.w, 30, tab.x + tab.w - r, 30);
ctx.lineTo(tab.x + r, 30);
ctx.quadraticCurveTo(tab.x, 30, tab.x, 30 - r);
ctx.lineTo(tab.x, 8 + r);
ctx.quadraticCurveTo(tab.x, 8, tab.x + r, 8);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.fillStyle = active ? '#000' : (active ? '#000' : mode.color);
ctx.font = 'bold 11px Courier New, monospace';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(tab.label, tab.x + tab.w / 2, 19);
}
// Monitor bezel
ctx.strokeStyle = '#003300';
ctx.lineWidth = 2;
ctx.fillStyle = '#000400';
ctx.beginPath();
ctx.roundRect(170, 60, 460, 200, 12);
ctx.fill();
ctx.stroke();
// Screen inner
ctx.fillStyle = '#001100';
ctx.beginPath();
ctx.roundRect(178, 68, 444, 180, 6);
ctx.fill();
// Stand
ctx.fillStyle = '#000400';
ctx.beginPath();
ctx.moveTo(370, 260);
ctx.lineTo(430, 260);
ctx.lineTo(415, 272);
ctx.lineTo(385, 272);
ctx.closePath();
ctx.fill();
// Base
ctx.fillStyle = '#000400';
ctx.fillRect(355, 272, 90, 6);
for (const feat of deskFeatList) {
ctx.fillStyle = '#00ff00';
ctx.font = '11px Courier New, monospace';
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillText(feat.label, feat.x, feat.y);
const locked = mode.locks[feat.id];
ctx.fillStyle = locked ? '#00ff00' : '#ff4444';
ctx.font = '14px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(locked ? '\u{1F512}' : '\u{1F513}', feat.lx, feat.y);
}
for (const pkt of deskPackets) {
let x, y;
if (pkt.orbit) {
const cx = 400, cy = 160;
x = cx + Math.cos(pkt.angle + pkt.progress * Math.PI * 2) * pkt.radius;
y = cy + Math.sin(pkt.angle + pkt.progress * Math.PI * 2) * pkt.radius * 0.6;
x = Math.max(185, Math.min(615, x));
y = Math.max(80, Math.min(250, y));
} else {
const t = pkt.progress;
if (t < 0.5) {
const p = t * 2;
x = 400 + (pkt.leakX - 400) * p;
y = 160 + (pkt.leakY - 160) * p;
} else {
const p = (t - 0.5) * 2;
x = pkt.leakX + (pkt.leakX - 400) * p;
y = pkt.leakY - 80 * p;
}
}
ctx.shadowColor = mode.color;
ctx.shadowBlur = 8;
ctx.fillStyle = mode.color;
ctx.beginPath();
ctx.arc(x, y, 4, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
pkt.progress += pkt.speed;
if (pkt.progress >= 1) {
pkt.progress = 0;
if (!pkt.orbit) {
pkt.leakX = 400 + (Math.random() - 0.5) * 200;
pkt.leakY = 30 + Math.random() * 40;
}
}
}
deskAnimId = requestAnimationFrame(drawDeskScene);
}
function handleDeskCanvasClick(mx, my) {
const canvas = document.getElementById('deskCanvas');
if (!canvas) return;
const rect = canvas.getBoundingClientRect();
const cx = (mx - rect.left) * (canvas.width / rect.width);
const cy = (my - rect.top) * (canvas.height / rect.height);
for (const tab of deskTabs) {
if (cx >= tab.x && cx <= tab.x + tab.w && cy >= 8 && cy <= 30) {
if (tab.id !== deskMode) {
deskMode = tab.id;
initDeskPackets();
const status = document.getElementById('deskStatus');
if (status) status.textContent = deskModeData[deskMode].status;
deskClicked = true;
const s7Row = document.getElementById('s7BtnRow');
if (s7Row.style.visibility !== 'visible') {
s7Row.style.cssText = '';
s7Row.style.visibility = 'visible';
let ro = 0;
const rfi = setInterval(() => {
ro += 0.05; if (ro >= 1) { ro = 1; clearInterval(rfi); s7Row.style.pointerEvents = 'auto'; }
s7Row.style.opacity = ro;
}, 30);
}
}
break;
}
}
}
function loadScene7(sceneElem) { function loadScene7(sceneElem) {
s7c=[]; s7c=[];
sceneElem.style.display='flex'; sceneElem.style.display='flex';
const txt=document.getElementById('s7Text'); const txt=document.getElementById('s7Text');
const vis=document.getElementById('s7Visual'); const canvasDiv=document.getElementById('s7Canvas');
txt.innerHTML=''; txt.innerHTML='';
vis.className='s7visual'; canvasDiv.classList.remove('visible');
if (deskAnimId) { cancelAnimationFrame(deskAnimId); deskAnimId = null; }
if (exfilDeskAnimId) { cancelAnimationFrame(exfilDeskAnimId); exfilDeskAnimId = null; }
const s7Row = document.getElementById('s7BtnRow');
s7Row.style.visibility = 'hidden';
s7Row.style.opacity = '0';
s7Row.style.pointerEvents = 'none';
let o=0; let o=0;
const fi=setInterval(()=>{ const fi=setInterval(()=>{
if (sceneElem.style.display !== 'flex' || document.getElementById('returnFromScene7').style.visibility === 'visible') { clearInterval(fi); return; } if (sceneElem.style.display !== 'flex' || document.getElementById('s7BtnRow').style.visibility === 'visible') { clearInterval(fi); return; }
o+=0.05;if(o>=1){o=1;clearInterval(fi); o+=0.05;if(o>=1){o=1;clearInterval(fi);
typeCalmly(txt,"DESKTOP COMPUTING IS DOMINATED BY CORPORATIONS THAT MONETIZE YOUR DATA AND RESTRICT YOUR FREEDOM.",()=>{ typeCalmly(txt,"YOUR DESKTOP OS DETERMINES WHO CONTROLS YOUR COMPUTER — YOU OR A CORPORATION.",()=>{
const t1=setTimeout(()=>{ const t1=setTimeout(()=>{
txt.innerHTML+="\n\n"; typeCalmly(txt,"\n\nCLICK A TAB TO SEE HOW EACH OS HANDLES SECURITY AND PRIVACY.",()=>{
vis.classList.add('visible'); const t2=setTimeout(()=>{
vis.innerHTML=buildS6DesktopTable(); canvasDiv.classList.add('visible');
typeCalmly(txt,"LINUX IS THE ONLY OS THAT RESPECTS YOUR FREEDOM — BECAUSE IT'S BUILT BY THE COMMUNITY, NOT A CORPORATION.",()=>{ initDeskScene();
const t3=setTimeout(()=>{ drawDeskScene();
document.getElementById('returnFromScene7').style.cssText=''; const status=document.getElementById('deskStatus');
showNextBtn('returnFromScene7'); if(status) status.textContent=deskModeData[deskMode].status;
},400);
s7c.push(t3);
},8,20,s7c);
},300); },300);
s7c.push(t2);
},8,20,s7c);
},600);
s7c.push(t1); s7c.push(t1);
},8,20,s7c); },8,20,s7c);
} }
@@ -2131,6 +2450,7 @@
let s8c = []; let s8c = [];
let s9c = []; let s9c = [];
let s8bc = []; let s8bc = [];
let s7bc = [];
// Scene 8b — Data Exfiltration Simulator // Scene 8b — Data Exfiltration Simulator
let exfilAnimId = null; let exfilAnimId = null;
@@ -2141,8 +2461,8 @@
const exfilModeData = { const exfilModeData = {
grapheneos: { label: 'GRAPHENEOS', counterMax: 0, color: '#00ff00', status: 'YOUR DATA STAYS ON YOUR DEVICE. NO TRACKING. NO PROFILING.' }, grapheneos: { label: 'GRAPHENEOS', counterMax: 0, color: '#00ff00', status: 'YOUR DATA STAYS ON YOUR DEVICE. NO TRACKING. NO PROFILING.' },
android: { label: 'ANDROID', counterMax: 1200, color: '#ff4444', status: 'GOOGLE AND THIRD-PARTY APPS COLLECT YOUR DATA BY DEFAULT. YOU ARE THE PRODUCT.' }, android: { label: 'ANDROID', counterMax: 200, color: '#ff4444', status: 'GOOGLE AND THIRD-PARTY APPS COLLECT YOUR DATA BY DEFAULT. YOU ARE THE PRODUCT.' },
ios: { label: 'iOS', counterMax: 600, color: '#ffff00', status: 'APPLE COLLECTS DATA THROUGH ITS SERVICES. SOME THIRD-PARTY TRACKING IS BLOCKED.' }, ios: { label: 'iOS', counterMax: 150, color: '#ffff00', status: 'APPLE COLLECTS DATA THROUGH ITS SERVICES. SOME THIRD-PARTY TRACKING IS BLOCKED.' },
}; };
const exfilTabs = [ const exfilTabs = [
@@ -2357,6 +2677,14 @@
const st = document.getElementById('exfilStatus'); const st = document.getElementById('exfilStatus');
if (st) st.textContent = mode.status; if (st) st.textContent = mode.status;
if (mode.counterMax > 0 && exfilCounter >= mode.counterMax && !window._exfilDone) {
window._exfilDone = true;
const rb = document.getElementById('returnFromScene8b');
if (rb) { rb.style.cssText = ''; showNextBtn('returnFromScene8b'); }
const sb = document.getElementById('sourcesFromScene8b');
if (sb) { sb.style.cssText = ''; showNextBtn('sourcesFromScene8b'); }
}
exfilAnimId = requestAnimationFrame(drawExfilScene); exfilAnimId = requestAnimationFrame(drawExfilScene);
} }
@@ -2372,6 +2700,13 @@
exfilMode = tab.id; exfilMode = tab.id;
exfilPackets = []; exfilPackets = [];
exfilCounterTarget = 0; exfilCounterTarget = 0;
window._exfilDone = false;
if (exfilModeData[exfilMode].counterMax === 0) {
const rb = document.getElementById('returnFromScene8b');
if (rb) { rb.style.cssText = ''; showNextBtn('returnFromScene8b'); }
const sb = document.getElementById('sourcesFromScene8b');
if (sb) { sb.style.cssText = ''; showNextBtn('sourcesFromScene8b'); }
}
} }
break; break;
} }
@@ -2408,6 +2743,289 @@
}, 30); }, 30);
} }
// Scene Refs tracking
window.refsCaller = null;
// Scene 7b — Desktop Exfiltration Simulator
let exfilDeskAnimId = null;
let exfilDeskMode = 'linux';
let exfilDeskPackets = [];
let exfilDeskCounter = 0;
let exfilDeskCounterTarget = 0;
const exfilDeskModeData = {
linux: { label: 'LINUX', counterMax: 0, color: '#00ff00', status: 'LINUX SENDS NO TELEMETRY. YOUR DATA STAYS ON YOUR MACHINE.' },
macos: { label: 'macOS', counterMax: 100, color: '#ffaa00', status: 'APPLE COLLECTS USAGE DATA AND CAN REMOTELY CONTROL YOUR DEVICE.' },
windows: { label: 'WINDOWS', counterMax: 150, color: '#ff4444', status: 'MICROSOFT COLLECTS EXTENSIVE TELEMETRY AND SHARES DATA WITH PARTNERS.' },
};
const exfilDeskTabs = [
{ id: 'linux', x: 170, w: 130, label: 'LINUX' },
{ id: 'macos', x: 335, w: 130, label: 'macOS' },
{ id: 'windows', x: 500, w: 130, label: 'WINDOWS' },
];
const exfilDeskServers = {
linux: [],
macos: [
{ id: 'apple', label: 'APPLE', x: 575, y: 65, w: 100, h: 34, color: '#aaaaaa' },
{ id: 'ads', label: 'AD NETWORKS', x: 555, y: 185, w: 115, h: 34, color: '#ff44ff' },
],
windows: [
{ id: 'ms', label: 'MICROSOFT', x: 535, y: 55, w: 110, h: 34, color: '#00a4ef' },
{ id: 'broker', label: 'DATA BROKER', x: 645, y: 115, w: 115, h: 34, color: '#ff6644' },
{ id: 'ads', label: 'AD NETWORKS', x: 560, y: 195, w: 115, h: 34, color: '#ff44ff' },
{ id: 'telemetry', label: 'TELEMETRY', x: 635, y: 285, w: 110, h: 34, color: '#ff0000' },
],
};
const exfilDeskDataTypes = [
{ id: 'telemetry', label: 'TELEMETRY', color: '#ff6644' },
{ id: 'browsing', label: 'BROWSING', color: '#44aaff' },
{ id: 'files', label: 'FILES', color: '#ff44ff' },
{ id: 'keystrokes', label: 'KEYSTROKES', color: '#ffff44' },
{ id: 'mic', label: 'MIC', color: '#44ffaa' },
{ id: 'location', label: 'LOCATION', color: '#ff8844' },
];
function initExfilDeskScene() {
exfilDeskMode = 'linux';
exfilDeskPackets = [];
exfilDeskCounter = 0;
exfilDeskCounterTarget = 0;
const legend = document.getElementById('exfilDeskLegend');
if (legend) {
legend.innerHTML = '';
for (const dt of exfilDeskDataTypes) {
const item = document.createElement('span');
item.className = 'exfil-legend-item';
item.innerHTML = '<span class="exfil-legend-dot" style="background:' + dt.color + '"></span>' + dt.label;
legend.appendChild(item);
}
}
}
function spawnExfilDeskPacket() {
const servers = exfilDeskServers[exfilDeskMode];
if (servers.length === 0) return;
const server = servers[Math.floor(Math.random() * servers.length)];
const dataType = exfilDeskDataTypes[Math.floor(Math.random() * exfilDeskDataTypes.length)];
const px = 80, py = 65, pw = 140, ph = 245;
const fromX = px + 10 + Math.random() * (pw - 20);
const fromY = py + 40 + Math.random() * (ph - 60);
const toX = server.x + Math.random() * server.w;
const toY = server.y + Math.random() * server.h;
exfilDeskPackets.push({
fromX, fromY, toX, toY,
dataType,
progress: 0,
speed: 0.008 + Math.random() * 0.006,
});
}
function drawExfilDeskScene() {
const canvas = document.getElementById('exfilDeskCanvas');
if (!canvas || canvas.offsetParent === null) { exfilDeskAnimId = requestAnimationFrame(drawExfilDeskScene); return; }
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
const mode = exfilDeskModeData[exfilDeskMode];
const servers = exfilDeskServers[exfilDeskMode];
// Tabs
for (const tab of exfilDeskTabs) {
const active = tab.id === exfilDeskMode;
ctx.fillStyle = active ? mode.color : '#001100';
ctx.strokeStyle = active ? mode.color : '#003300';
ctx.lineWidth = active ? 2 : 1;
const r = 4;
ctx.beginPath();
ctx.moveTo(tab.x + r, 8);
ctx.lineTo(tab.x + tab.w - r, 8);
ctx.quadraticCurveTo(tab.x + tab.w, 8, tab.x + tab.w, 8 + r);
ctx.lineTo(tab.x + tab.w, 30 - r);
ctx.quadraticCurveTo(tab.x + tab.w, 30, tab.x + tab.w - r, 30);
ctx.lineTo(tab.x + r, 30);
ctx.quadraticCurveTo(tab.x, 30, tab.x, 30 - r);
ctx.lineTo(tab.x, 8 + r);
ctx.quadraticCurveTo(tab.x, 8, tab.x + r, 8);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.fillStyle = active ? '#000' : mode.color;
ctx.font = 'bold 11px Courier New, monospace';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(tab.label, tab.x + tab.w / 2, 19);
}
// Monitor silhouette
const px = 70, py = 55, pw = 140, ph = 245;
ctx.shadowColor = mode.color;
ctx.shadowBlur = 15;
ctx.strokeStyle = mode.color;
ctx.lineWidth = 2;
ctx.fillStyle = '#000800';
ctx.beginPath();
ctx.roundRect(px, py, pw, ph, 18);
ctx.fill();
ctx.stroke();
ctx.shadowBlur = 0;
ctx.fillStyle = '#001100';
ctx.beginPath();
ctx.roundRect(px + 8, py + 35, pw - 16, ph - 55, 6);
ctx.fill();
ctx.fillStyle = mode.color;
ctx.font = 'bold 12px Courier New, monospace';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(exfilDeskMode === 'linux' ? 'SECURE' : 'LEAKING', px + pw / 2, py + ph / 2);
// Servers + connection lines
for (const srv of servers) {
ctx.strokeStyle = srv.color + '22';
ctx.lineWidth = 1;
ctx.setLineDash([4, 6]);
ctx.beginPath();
ctx.moveTo(px + pw / 2, py + ph / 2);
ctx.lineTo(srv.x + srv.w / 2, srv.y + srv.h / 2);
ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = srv.color + '33';
ctx.strokeStyle = srv.color;
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.roundRect(srv.x, srv.y, srv.w, srv.h, 4);
ctx.fill();
ctx.stroke();
ctx.fillStyle = srv.color;
ctx.font = 'bold 10px Courier New, monospace';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(srv.label, srv.x + srv.w / 2, srv.y + srv.h / 2);
}
if (servers.length > 0 && Math.random() < 0.06) spawnExfilDeskPacket();
for (let i = exfilDeskPackets.length - 1; i >= 0; i--) {
const pkt = exfilDeskPackets[i];
const x = pkt.fromX + (pkt.toX - pkt.fromX) * pkt.progress;
const y = pkt.fromY + (pkt.toY - pkt.fromY) * pkt.progress;
ctx.strokeStyle = pkt.dataType.color + '44';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(pkt.fromX, pkt.fromY);
ctx.lineTo(x, y);
ctx.stroke();
ctx.shadowColor = pkt.dataType.color;
ctx.shadowBlur = 10;
ctx.fillStyle = pkt.dataType.color;
ctx.beginPath();
ctx.arc(x, y, 5, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0;
ctx.fillStyle = pkt.dataType.color;
ctx.font = '8px Courier New, monospace';
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillText(pkt.dataType.label, x, y - 6);
pkt.progress += pkt.speed;
if (pkt.progress >= 1) {
exfilDeskPackets.splice(i, 1);
if (exfilDeskCounterTarget < mode.counterMax) {
exfilDeskCounterTarget = Math.min(mode.counterMax, exfilDeskCounterTarget + 18);
}
}
}
while (exfilDeskPackets.length > 30) exfilDeskPackets.shift();
if (exfilDeskCounter < exfilDeskCounterTarget) {
exfilDeskCounter = Math.min(exfilDeskCounterTarget, exfilDeskCounter + 5);
} else if (exfilDeskCounter > exfilDeskCounterTarget) {
exfilDeskCounter = Math.max(exfilDeskCounterTarget, exfilDeskCounter - 5);
}
const ce = document.getElementById('exfilDeskCounter');
if (ce) {
ce.textContent = 'DATA VALUE EXPOSED: $' + exfilDeskCounter.toFixed(0) + '/yr';
ce.style.color = exfilDeskCounter > 0 ? '#ff4444' : '#00ff00';
}
const st = document.getElementById('exfilDeskStatus');
if (st) st.textContent = mode.status;
if (mode.counterMax > 0 && exfilDeskCounter >= mode.counterMax && !window._exfilDeskDone) {
window._exfilDeskDone = true;
const rb = document.getElementById('returnFromScene7b');
if (rb) { rb.style.cssText = ''; showNextBtn('returnFromScene7b'); }
const sb = document.getElementById('sourcesFromScene7b');
if (sb) { sb.style.cssText = ''; showNextBtn('sourcesFromScene7b'); }
}
exfilDeskAnimId = requestAnimationFrame(drawExfilDeskScene);
}
function handleExfilDeskCanvasClick(mx, my) {
const canvas = document.getElementById('exfilDeskCanvas');
if (!canvas) return;
const rect = canvas.getBoundingClientRect();
const cx = (mx - rect.left) * (canvas.width / rect.width);
const cy = (my - rect.top) * (canvas.height / rect.height);
for (const tab of exfilDeskTabs) {
if (cx >= tab.x && cx <= tab.x + tab.w && cy >= 8 && cy <= 30) {
if (tab.id !== exfilDeskMode) {
exfilDeskMode = tab.id;
exfilDeskPackets = [];
exfilDeskCounterTarget = 0;
window._exfilDeskDone = false;
if (exfilDeskModeData[exfilDeskMode].counterMax === 0) {
const rb = document.getElementById('returnFromScene7b');
if (rb) { rb.style.cssText = ''; showNextBtn('returnFromScene7b'); }
const sb = document.getElementById('sourcesFromScene7b');
if (sb) { sb.style.cssText = ''; showNextBtn('sourcesFromScene7b'); }
}
}
break;
}
}
}
function loadScene7b(sceneElem) {
s7bc = [];
sceneElem.style.display = 'flex';
const txt = document.getElementById('s7bText');
const canvasDiv = document.getElementById('s7bCanvas');
txt.innerHTML = '';
canvasDiv.classList.remove('visible');
if (exfilDeskAnimId) { cancelAnimationFrame(exfilDeskAnimId); exfilDeskAnimId = null; }
let o = 0;
const fi = setInterval(() => {
if (sceneElem.style.display !== 'flex' || document.getElementById('returnFromScene7b').style.visibility === 'visible') { clearInterval(fi); return; }
o += 0.05; if (o >= 1) { o = 1; clearInterval(fi);
typeCalmly(txt, "EVERY CLICK, EVERY KEYSTROKE, EVERY FILE YOU OPEN — YOUR OS MAY BE REPORTING IT ALL TO CORPORATE SERVERS.", () => {
const t1 = setTimeout(() => {
typeCalmly(txt, "\n\nCLICK THE TABS TO SEE WHERE YOUR DATA ACTUALLY GOES.", () => {
const t2 = setTimeout(() => {
canvasDiv.classList.add('visible');
initExfilDeskScene();
drawExfilDeskScene();
}, 300);
s7bc.push(t2);
}, 8, 20, s7bc);
}, 600);
s7bc.push(t1);
}, 8, 20, s7bc);
}
sceneElem.style.opacity = o;
}, 30);
}
// Initialize on load // Initialize on load
window.addEventListener('load', () => { window.addEventListener('load', () => {
setTimeout(crtFlicker, 1500); setTimeout(crtFlicker, 1500);
@@ -2508,6 +3126,8 @@
if (meshAnimId) { cancelAnimationFrame(meshAnimId); meshAnimId = null; } if (meshAnimId) { cancelAnimationFrame(meshAnimId); meshAnimId = null; }
if (phoneAnimId) { cancelAnimationFrame(phoneAnimId); phoneAnimId = null; } if (phoneAnimId) { cancelAnimationFrame(phoneAnimId); phoneAnimId = null; }
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; } if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
if (deskAnimId) { cancelAnimationFrame(deskAnimId); deskAnimId = null; }
if (exfilDeskAnimId) { cancelAnimationFrame(exfilDeskAnimId); exfilDeskAnimId = null; }
const s6 = document.getElementById('scene6'); const s6 = document.getElementById('scene6');
s6.style.display = 'flex'; s6.style.display = 'flex';
s6.style.opacity = '1'; s6.style.opacity = '1';
@@ -2542,10 +3162,37 @@
handlePhoneCanvasClick(e.clientX, e.clientY); handlePhoneCanvasClick(e.clientX, e.clientY);
}); });
document.getElementById('deskCanvas').addEventListener('click', (e) => {
handleDeskCanvasClick(e.clientX, e.clientY);
});
document.getElementById('exfilCanvas').addEventListener('click', (e) => { document.getElementById('exfilCanvas').addEventListener('click', (e) => {
handleExfilCanvasClick(e.clientX, e.clientY); handleExfilCanvasClick(e.clientX, e.clientY);
}); });
document.getElementById('exfilDeskCanvas').addEventListener('click', (e) => {
handleExfilDeskCanvasClick(e.clientX, e.clientY);
});
document.getElementById('nextFromScene7').addEventListener('click', () => {
if (exfilDeskAnimId) { cancelAnimationFrame(exfilDeskAnimId); exfilDeskAnimId = null; }
if (deskAnimId) { cancelAnimationFrame(deskAnimId); deskAnimId = null; }
document.getElementById('scene7').style.display = 'none';
loadScene7b(document.getElementById('scene7b'));
});
document.getElementById('sourcesFromScene7b').addEventListener('click', () => {
refsCaller = 'scene7b';
document.getElementById('scene7b').style.display = 'none';
document.getElementById('sceneRefs').classList.add('visible');
});
document.getElementById('returnFromScene7b').addEventListener('click', () => {
if (exfilDeskAnimId) { cancelAnimationFrame(exfilDeskAnimId); exfilDeskAnimId = null; }
document.getElementById('scene7b').style.display = 'none';
showTechHub();
});
document.getElementById('nextFromScene8').addEventListener('click', () => { document.getElementById('nextFromScene8').addEventListener('click', () => {
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; } if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
if (phoneAnimId) { cancelAnimationFrame(phoneAnimId); phoneAnimId = null; } if (phoneAnimId) { cancelAnimationFrame(phoneAnimId); phoneAnimId = null; }
@@ -2553,6 +3200,12 @@
loadScene8b(document.getElementById('scene8b')); loadScene8b(document.getElementById('scene8b'));
}); });
document.getElementById('sourcesFromScene8b').addEventListener('click', () => {
refsCaller = 'scene8b';
document.getElementById('scene8b').style.display = 'none';
document.getElementById('sceneRefs').classList.add('visible');
});
document.getElementById('returnFromScene8b').addEventListener('click', () => { document.getElementById('returnFromScene8b').addEventListener('click', () => {
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; } if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
document.getElementById('scene8b').style.display = 'none'; document.getElementById('scene8b').style.display = 'none';
@@ -2562,6 +3215,19 @@
// Keyboard shortcuts for testing // Keyboard shortcuts for testing
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') { if (e.key === 'Escape') {
// SceneRefs: return to caller
const refsDiv = document.getElementById('sceneRefs');
if (refsDiv.classList.contains('visible')) {
refsDiv.classList.remove('visible');
if (refsCaller === 'scene7b') {
document.getElementById('scene7b').style.display = 'flex';
} else if (refsCaller === 'scene8b') {
document.getElementById('scene8b').style.display = 'flex';
}
refsCaller = null;
return;
}
// Escape alone: Skip current animation to text // Escape alone: Skip current animation to text
// Scene 1 skip (rain or typewriter) // Scene 1 skip (rain or typewriter)
@@ -2698,12 +3364,18 @@
if (s7.style.display === 'flex') { if (s7.style.display === 'flex') {
s7c.forEach(t => clearTimeout(t)); s7c = []; s7c.forEach(t => clearTimeout(t)); s7c = [];
const txt = document.getElementById('s7Text'); const txt = document.getElementById('s7Text');
const vis = document.getElementById('s7Visual'); txt.innerHTML = "YOUR DESKTOP OS DETERMINES WHO CONTROLS YOUR COMPUTER — YOU OR A CORPORATION.\n\nCLICK A TAB TO SEE HOW EACH OS HANDLES SECURITY AND PRIVACY.";
txt.innerHTML = "DESKTOP COMPUTING IS DOMINATED BY CORPORATIONS THAT MONETIZE YOUR DATA AND RESTRICT YOUR FREEDOM.\n\nLINUX IS THE ONLY OS THAT RESPECTS YOUR FREEDOM — BECAUSE IT'S BUILT BY THE COMMUNITY, NOT A CORPORATION."; const canvasDiv = document.getElementById('s7Canvas');
vis.innerHTML=buildS6DesktopTable(); canvasDiv.classList.add('visible');
vis.classList.add('visible'); if (deskAnimId) { cancelAnimationFrame(deskAnimId); deskAnimId = null; }
document.getElementById('returnFromScene7').style.cssText=''; if (exfilDeskAnimId) { cancelAnimationFrame(exfilDeskAnimId); exfilDeskAnimId = null; }
showNextBtn('returnFromScene7'); initDeskScene();
drawDeskScene();
const s7Row = document.getElementById('s7BtnRow');
s7Row.style.cssText = '';
s7Row.style.visibility = 'visible';
s7Row.style.opacity = '1';
s7Row.style.pointerEvents = 'auto';
} }
// Scene 8 skip // Scene 8 skip
@@ -2751,8 +3423,29 @@
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; } if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
initExfilScene(); initExfilScene();
drawExfilScene(); drawExfilScene();
window._exfilDone = true;
document.getElementById('returnFromScene8b').style.cssText=''; document.getElementById('returnFromScene8b').style.cssText='';
showNextBtn('returnFromScene8b'); showNextBtn('returnFromScene8b');
document.getElementById('sourcesFromScene8b').style.cssText='';
showNextBtn('sourcesFromScene8b');
}
// Scene 7b skip
const s7b = document.getElementById('scene7b');
if (s7b.style.display === 'flex') {
s7bc.forEach(t => clearTimeout(t)); s7bc = [];
const txt = document.getElementById('s7bText');
txt.innerHTML = "EVERY CLICK, EVERY KEYSTROKE, EVERY FILE YOU OPEN — YOUR OS MAY BE REPORTING IT ALL TO CORPORATE SERVERS.\n\nCLICK THE TABS TO SEE WHERE YOUR DATA ACTUALLY GOES.";
const canvasDiv = document.getElementById('s7bCanvas');
canvasDiv.classList.add('visible');
if (exfilDeskAnimId) { cancelAnimationFrame(exfilDeskAnimId); exfilDeskAnimId = null; }
initExfilDeskScene();
drawExfilDeskScene();
window._exfilDeskDone = true;
document.getElementById('returnFromScene7b').style.cssText='';
showNextBtn('returnFromScene7b');
document.getElementById('sourcesFromScene7b').style.cssText='';
showNextBtn('sourcesFromScene7b');
} }
} }
@@ -2767,5 +3460,26 @@
} }
}); });
</script> </script>
<!-- Scene Refs -->
<div id="sceneRefs">
<div class="refs-content">
<h2>SOURCES</h2>
<ol>
<li><a href="https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0001652044&type=10-K" target="_blank">Alphabet Inc. 2025 Form 10-K, SEC EDGAR</a> — Google advertising revenue used for ad ARPU estimation (~$90100/user/year).</li>
<li><a href="https://www.computerworld.com/article/1615208/apple-services-arpu.html" target="_blank">Computerworld — Apple Services ARPU estimated at ~$72/user/year (Morgan Stanley analysis).</a></li>
<li><a href="https://www.grandviewresearch.com/industry-analysis/data-broker-market" target="_blank">Grand View Research — Data Broker Market Size Report ($365B market, ~$46/user/year secondary value estimate).</a></li>
<li><a href="https://www.microsoft.com/en-us/Investor" target="_blank">Microsoft Investor Relations — Search advertising revenue ~$16B annually (~$11/user/year).</a></li>
<li><a href="https://learn.microsoft.com/en-us/windows/privacy/configure-windows-diagnostic-data-in-your-organization" target="_blank">Microsoft Learn — Windows diagnostic data levels (required vs optional telemetry).</a></li>
<li><a href="https://grapheneos.org/" target="_blank">GrapheneOS — Privacy-focused mobile OS with no data collection infrastructure.</a></li>
<li><a href="https://policies.google.com/technologies/ads" target="_blank">Google — How Google uses cookies in advertising (DoubleClick tracking infrastructure).</a></li>
<li><a href="https://developer.apple.com/app-store/user-privacy-and-data-use/" target="_blank">Apple Developer — App Tracking Transparency framework and user privacy controls.</a></li>
<li><a href="https://support.apple.com/guide/mac-help/system-integrity-protection-mac-mh35976/mac" target="_blank">Apple Support — macOS System Integrity Protection (SIP) overview.</a></li>
<li><a href="https://learn.microsoft.com/en-us/windows/privacy/" target="_blank">Microsoft Learn — Windows privacy controls and data collection policies overview.</a></li>
</ol>
<div class="refs-back"><button id="refsBackBtn" onclick="document.getElementById('sceneRefs').classList.remove('visible');if(window.refsCaller==='scene7b'){document.getElementById('scene7b').style.display='flex'}else if(window.refsCaller==='scene8b'){document.getElementById('scene8b').style.display='flex'};window.refsCaller=null;">BACK</button></div>
</div>
</div>
</body> </body>
</html> </html>