4004 lines
186 KiB
HTML
4004 lines
186 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Signal Elsewhere</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
background-color: #000;
|
||
overflow: hidden;
|
||
font-family: 'Courier New', monospace;
|
||
}
|
||
|
||
#matrixCanvas {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
z-index: 1;
|
||
opacity: 1;
|
||
transition: opacity 1s ease;
|
||
}
|
||
|
||
#textContainer {
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
z-index: 2;
|
||
text-align: center;
|
||
font-size: 1.2rem;
|
||
line-height: 2;
|
||
visibility: hidden;
|
||
color: #00ff00;
|
||
}
|
||
|
||
.typewriter-line {
|
||
visibility: hidden;
|
||
white-space: nowrap;
|
||
margin: 0.5rem 0;
|
||
}
|
||
|
||
#followBtn {
|
||
position: fixed;
|
||
bottom: 5%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 3;
|
||
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;
|
||
}
|
||
|
||
#followBtn:hover {
|
||
background-color: #003300;
|
||
}
|
||
|
||
.scene {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
z-index: 4;
|
||
background-color: #000;
|
||
color: #00ff00;
|
||
display: none;
|
||
justify-content: center;
|
||
align-items: center;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 1.2rem;
|
||
text-align: center;
|
||
padding: 2rem;
|
||
opacity: 0;
|
||
transition: opacity 1s ease;
|
||
}
|
||
|
||
#scene2 {
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
position: relative;
|
||
}
|
||
|
||
#scene2Lines {
|
||
display: none;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 100%;
|
||
}
|
||
|
||
#scene2Line1 {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 1.2rem;
|
||
line-height: 1.8;
|
||
color: #00ff00;
|
||
visibility: hidden;
|
||
padding: 2rem;
|
||
text-align: center;
|
||
}
|
||
|
||
#scene2Line2 {
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 1.2rem;
|
||
line-height: 1.8;
|
||
color: #00ff00;
|
||
padding: 0 2rem 2rem;
|
||
text-align: center;
|
||
}
|
||
|
||
#scene2Message2 {
|
||
color: #00ff00;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 1.2rem;
|
||
}
|
||
|
||
#scene2Cursor,
|
||
#scene2Cursor2 {
|
||
display: none;
|
||
width: 10px;
|
||
height: 1.4em;
|
||
background-color: #00ff00;
|
||
margin-left: 4px;
|
||
flex-shrink: 0;
|
||
opacity: 1;
|
||
}
|
||
|
||
#whatIsLabBtn {
|
||
position: fixed;
|
||
bottom: 5%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 3;
|
||
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;
|
||
}
|
||
|
||
#whatIsLabBtn:hover {
|
||
background-color: #003300;
|
||
}
|
||
|
||
#scene3ChoiceRow {
|
||
position: fixed;
|
||
bottom: 25%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 3;
|
||
display: none;
|
||
flex-direction: row;
|
||
gap: 1rem;
|
||
justify-content: center;
|
||
}
|
||
|
||
.scene3ChoiceBtn {
|
||
padding: 1rem 2rem;
|
||
font-size: 1rem;
|
||
background-color: #001100;
|
||
color: #00ff00;
|
||
border: 2px solid #00ff00;
|
||
cursor: pointer;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: opacity 0.8s ease, background-color 0.2s ease;
|
||
font-family: 'Courier New', monospace;
|
||
letter-spacing: 2px;
|
||
}
|
||
|
||
.scene3ChoiceBtn:hover {
|
||
background-color: #003300;
|
||
}
|
||
|
||
#scene4 {
|
||
flex-direction: column;
|
||
justify-content: flex-start;
|
||
align-items: flex-start;
|
||
padding: 2rem;
|
||
}
|
||
|
||
#scene4Text {
|
||
white-space: pre-wrap;
|
||
}
|
||
|
||
#scene3Title {
|
||
position: absolute;
|
||
top: 2rem;
|
||
left: 2rem;
|
||
font-size: 3rem;
|
||
font-weight: bold;
|
||
color: #00ff00;
|
||
opacity: 0;
|
||
transition: opacity 1.5s ease-out;
|
||
}
|
||
|
||
#scene3Title.visible {
|
||
opacity: 1;
|
||
}
|
||
|
||
#scene3 {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
justify-content: flex-start;
|
||
padding: 6rem 2rem;
|
||
}
|
||
|
||
#scene3Text {
|
||
white-space: pre-wrap;
|
||
margin-top: 2.4rem;
|
||
width: 100%;
|
||
}
|
||
|
||
/* Scene 4 sub-scenes */
|
||
.scene4sub {
|
||
flex-direction: column;
|
||
justify-content: flex-start;
|
||
align-items: center;
|
||
padding: 8rem 2rem 1.5rem;
|
||
overflow-y: auto;
|
||
}
|
||
.scene4text {
|
||
white-space: pre-wrap;
|
||
text-align: left;
|
||
width: 100%;
|
||
max-width: 50rem;
|
||
line-height: 1.8;
|
||
}
|
||
.s4visual {
|
||
width: 100%;
|
||
max-width: 50rem;
|
||
margin-top: 1.5rem;
|
||
opacity: 0;
|
||
transition: opacity 1.2s ease;
|
||
}
|
||
.s4visual.visible { opacity: 1; }
|
||
|
||
/* Timeline */
|
||
.s4tl {
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
width: 100%;
|
||
max-width: 50rem;
|
||
margin-bottom: 1.5rem;
|
||
padding: 0.5rem 0;
|
||
border-bottom: 1px solid #003300;
|
||
opacity: 0;
|
||
transition: opacity 1s ease;
|
||
}
|
||
.s4tl.visible { opacity: 1; }
|
||
.tl-year {
|
||
font-size: 0.85rem;
|
||
color: #004400;
|
||
transition: color 0.8s ease;
|
||
cursor: default;
|
||
position: relative;
|
||
}
|
||
.tl-year.active { color: #00ff00; }
|
||
.tl-year.dim { color: #007700; }
|
||
.tl-year::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: -0.3rem;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 50%;
|
||
background: #004400;
|
||
transition: background 0.8s ease;
|
||
}
|
||
.tl-year.active::after { background: #00ff00; box-shadow: 0 0 6px #00ff00; }
|
||
.tl-year.dim::after { background: #007700; }
|
||
|
||
/* 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 {
|
||
position: fixed;
|
||
bottom: 5%;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 5;
|
||
padding: 0.8rem 2.5rem;
|
||
font-size: 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;
|
||
}
|
||
.btnNext:hover { background-color: #003300; }
|
||
|
||
/* 69% Callout box */
|
||
.callout-box {
|
||
border: 2px solid #660000;
|
||
background: #1a0000;
|
||
color: #ff4444;
|
||
padding: 1.2rem 1.5rem;
|
||
text-align: center;
|
||
font-weight: bold;
|
||
font-size: 1.1rem;
|
||
border-radius: 4px;
|
||
box-shadow: 0 0 12px rgba(255,0,0,0.15);
|
||
animation: calloutPulse 2s infinite alternate;
|
||
}
|
||
@keyframes calloutPulse {
|
||
from { box-shadow: 0 0 8px rgba(255,0,0,0.1); }
|
||
to { box-shadow: 0 0 20px rgba(255,0,0,0.3); }
|
||
}
|
||
|
||
/* Coin stack */
|
||
.coin-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(10, 1fr);
|
||
gap: 4px;
|
||
max-width: 15rem;
|
||
margin: 0 auto;
|
||
}
|
||
.coin {
|
||
aspect-ratio: 1;
|
||
border-radius: 50%;
|
||
border: 1px solid #004400;
|
||
background: #001100;
|
||
transition: background 0.5s ease, border-color 0.5s ease;
|
||
}
|
||
.coin.gold { background: #665500; border-color: #aa8800; }
|
||
|
||
/* Comparison table */
|
||
.comp-table {
|
||
width: 100%;
|
||
max-width: 50rem;
|
||
border-collapse: collapse;
|
||
margin-top: 1rem;
|
||
font-size: 0.9rem;
|
||
}
|
||
.comp-table th, .comp-table td {
|
||
border: 1px solid #003300;
|
||
padding: 0.6rem 1rem;
|
||
text-align: center;
|
||
}
|
||
.comp-table th {
|
||
color: #00ff00;
|
||
border-bottom: 2px solid #00ff00;
|
||
}
|
||
.comp-table td:first-child {
|
||
text-align: left;
|
||
color: #00cc00;
|
||
}
|
||
.comp-table .yes { color: #ff4444; }
|
||
.comp-table .no { color: #44ff44; }
|
||
|
||
/* Punch cards */
|
||
.punch-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
gap: 1rem;
|
||
justify-content: center;
|
||
margin-top: 1.5rem;
|
||
width: 100%;
|
||
max-width: 50rem;
|
||
}
|
||
.punch-card {
|
||
flex: 1;
|
||
border: 1px solid #003300;
|
||
padding: 1rem;
|
||
text-align: center;
|
||
font-size: 0.85rem;
|
||
background: #000800;
|
||
border-radius: 4px;
|
||
}
|
||
.punch-card .punch-icon {
|
||
font-size: 1.5rem;
|
||
display: block;
|
||
margin-bottom: 0.4rem;
|
||
}
|
||
.punch-card .punch-text {
|
||
color: #00ff00;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
/* Scene 5 */
|
||
.scene5text {
|
||
white-space: pre-wrap;
|
||
text-align: left;
|
||
width: 100%;
|
||
max-width: 55rem;
|
||
line-height: 1.8;
|
||
}
|
||
.s5visual {
|
||
width: 100%;
|
||
max-width: 55rem;
|
||
margin-top: 1.5rem;
|
||
opacity: 0;
|
||
transition: opacity 4s ease;
|
||
}
|
||
.s5visual.visible { opacity: 1; }
|
||
|
||
/* Hashrate dominance bar */
|
||
.hash-bar-container {
|
||
width: 100%;
|
||
max-width: 40rem;
|
||
margin: 0 auto;
|
||
}
|
||
.hash-bar {
|
||
display: flex;
|
||
height: 2.8rem;
|
||
border: 1px solid #003300;
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
.hash-bar-btc {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: linear-gradient(90deg, #003300, #00ff00);
|
||
color: #000;
|
||
font-weight: bold;
|
||
font-size: 0.9rem;
|
||
flex: 99;
|
||
text-shadow: 0 0 4px #00ff00;
|
||
transition: flex 1.5s ease;
|
||
}
|
||
.hash-bar-rest {
|
||
flex: 1;
|
||
background: #1a0000;
|
||
border-left: 1px solid #003300;
|
||
}
|
||
|
||
/* Table row highlight for BTC */
|
||
.comp-table .btc-col {
|
||
background: #001a00;
|
||
border-color: #00ff00;
|
||
color: #00ff00;
|
||
font-weight: bold;
|
||
}
|
||
.comp-table .btc-col .yes { color: #44ff44; }
|
||
.comp-table .btc-col .no { color: #ff4444; }
|
||
.comp-table .nickname {
|
||
font-size: 0.75rem;
|
||
color: #007700;
|
||
}
|
||
.comp-table th.btc-col {
|
||
border-bottom-color: #00ff00;
|
||
}
|
||
.comp-table td.btc-col .no { color: #44ff44; }
|
||
.comp-table td.btc-col .yes { color: #ff4444; }
|
||
|
||
/* Scene 6 — Tech Hub */
|
||
#s6TechHub {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 1.2rem;
|
||
}
|
||
.hub-title {
|
||
font-size: 2rem;
|
||
font-weight: bold;
|
||
color: #00ff00;
|
||
margin-bottom: 1rem;
|
||
opacity: 0;
|
||
transition: opacity 1.5s ease;
|
||
}
|
||
.hub-title.visible { opacity: 1; }
|
||
.hub-subtitle {
|
||
font-size: 1rem;
|
||
color: #007700;
|
||
margin-bottom: 0.5rem;
|
||
opacity: 0;
|
||
transition: opacity 1.5s ease;
|
||
}
|
||
.hub-subtitle.visible { opacity: 1; }
|
||
.hub-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 2rem;
|
||
width: 100%;
|
||
max-width: 40rem;
|
||
padding: 1rem 2rem;
|
||
border: 1px solid #003300;
|
||
background: #000800;
|
||
border-radius: 4px;
|
||
opacity: 0;
|
||
transition: opacity 1s ease;
|
||
}
|
||
.hub-row.visible { opacity: 1; }
|
||
.hub-label {
|
||
color: #00ff00;
|
||
font-size: 1rem;
|
||
}
|
||
.hub-btn {
|
||
padding: 0.6rem 2rem;
|
||
font-size: 0.9rem;
|
||
background-color: #001100;
|
||
color: #00ff00;
|
||
border: 2px solid #00ff00;
|
||
cursor: pointer;
|
||
font-family: 'Courier New', monospace;
|
||
letter-spacing: 2px;
|
||
transition: background-color 0.2s ease;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
.hub-btn.visible {
|
||
opacity: 1;
|
||
pointer-events: auto;
|
||
}
|
||
.hub-btn:hover { background-color: #003300; }
|
||
.hub-return {
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
/* Scene 7 — Desktop OS comparison */
|
||
.scene7text {
|
||
white-space: pre-wrap;
|
||
text-align: left;
|
||
width: 100%;
|
||
max-width: 55rem;
|
||
line-height: 1.8;
|
||
}
|
||
.s7visual {
|
||
width: 100%;
|
||
max-width: 55rem;
|
||
margin-top: 1.5rem;
|
||
opacity: 0;
|
||
transition: opacity 4s ease;
|
||
}
|
||
.s7visual.visible { opacity: 1; }
|
||
|
||
/* Scene 8 — Mobile OS + decentralized internet */
|
||
.scene8text {
|
||
white-space: pre-wrap;
|
||
text-align: left;
|
||
width: 100%;
|
||
max-width: 55rem;
|
||
line-height: 1.8;
|
||
}
|
||
.s8visual {
|
||
width: 100%;
|
||
max-width: 55rem;
|
||
margin-top: 1.5rem;
|
||
opacity: 0;
|
||
transition: opacity 4s ease;
|
||
}
|
||
.s8visual.visible { opacity: 1; }
|
||
#s9Text { text-align: center; }
|
||
.s9canvas {
|
||
width: 100%;
|
||
max-width: 55rem;
|
||
margin-top: 1.5rem;
|
||
opacity: 0;
|
||
transition: opacity 4s ease;
|
||
}
|
||
.s9canvas.visible { opacity: 1; }
|
||
#meshCanvas {
|
||
width: 100%;
|
||
height: 320px;
|
||
border: 1px solid #003300;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
display: block;
|
||
}
|
||
.mesh-legend {
|
||
display: flex;
|
||
gap: 2rem;
|
||
justify-content: center;
|
||
margin-top: 0.8rem;
|
||
font-size: 0.8rem;
|
||
}
|
||
.legend-item { display: flex; align-items: center; gap: 0.5rem; }
|
||
.legend-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
|
||
.legend-dot.online { background: #00ff00; }
|
||
.legend-dot.offline { background: #ff4444; }
|
||
.legend-dot.packet { background: #ffff00; }
|
||
.mesh-status {
|
||
text-align: center;
|
||
color: #007700;
|
||
font-size: 0.85rem;
|
||
margin-top: 0.5rem;
|
||
min-height: 1.5rem;
|
||
}
|
||
.s8canvas {
|
||
width: 100%;
|
||
max-width: 55rem;
|
||
margin-top: 0.8rem;
|
||
opacity: 0;
|
||
transition: opacity 4s ease;
|
||
}
|
||
.s8canvas.visible { opacity: 1; }
|
||
#phoneCanvas {
|
||
width: 100%;
|
||
height: 320px;
|
||
border: 1px solid #003300;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
display: block;
|
||
}
|
||
|
||
.s6section {
|
||
margin-top: 1.5rem;
|
||
text-align: left;
|
||
}
|
||
.s6section-title {
|
||
color: #007700;
|
||
font-size: 0.85rem;
|
||
margin-bottom: 0.5rem;
|
||
text-align: center;
|
||
}
|
||
|
||
.comp-table .linux-col {
|
||
background: #001a00;
|
||
border-color: #00ff00;
|
||
color: #00ff00;
|
||
font-weight: bold;
|
||
}
|
||
.comp-table .linux-col .no { color: #44ff44; }
|
||
.comp-table .linux-col .yes { color: #ff4444; }
|
||
.comp-table th.linux-col {
|
||
border-bottom-color: #00ff00;
|
||
}
|
||
.comp-table td.linux-col .no { color: #44ff44; }
|
||
.comp-table td.linux-col .yes { color: #ff4444; }
|
||
|
||
.comp-table .graphene-col {
|
||
background: #001a00;
|
||
border-color: #00ff00;
|
||
color: #00ff00;
|
||
font-weight: bold;
|
||
}
|
||
.comp-table .graphene-col .no { color: #44ff44; }
|
||
.comp-table .graphene-col .yes { color: #ff4444; }
|
||
.comp-table th.graphene-col {
|
||
border-bottom-color: #00ff00;
|
||
}
|
||
.comp-table td.graphene-col .no { color: #44ff44; }
|
||
.comp-table td.graphene-col .yes { color: #ff4444; }
|
||
|
||
/* Scene 8b — Exfiltration Simulator */
|
||
#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;
|
||
}
|
||
#s8BtnRow .btnNext {
|
||
position: static;
|
||
transform: none;
|
||
margin: 0;
|
||
visibility: visible;
|
||
opacity: 1;
|
||
pointer-events: auto;
|
||
}
|
||
.s8bcanvas {
|
||
width: 100%;
|
||
max-width: 55rem;
|
||
margin-top: 0.8rem;
|
||
opacity: 0;
|
||
transition: opacity 4s ease;
|
||
}
|
||
.s8bcanvas.visible { opacity: 1; }
|
||
#exfilCanvas {
|
||
width: 100%;
|
||
height: 360px;
|
||
border: 1px solid #003300;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
display: block;
|
||
}
|
||
.exfil-counter {
|
||
text-align: center;
|
||
color: #00ff00;
|
||
font-size: 1.1rem;
|
||
padding: 0.5rem;
|
||
min-height: 2rem;
|
||
font-weight: bold;
|
||
}
|
||
.exfil-legend {
|
||
display: flex;
|
||
gap: 1rem;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
margin-top: 0.3rem;
|
||
font-size: 0.75rem;
|
||
}
|
||
.exfil-legend-item { display: flex; align-items: center; gap: 0.3rem; }
|
||
.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; }
|
||
|
||
/* YOUR FOOD overlay */
|
||
#foodOverlay {
|
||
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
||
z-index: 200;
|
||
display: none; justify-content: center; align-items: center;
|
||
background: rgba(0,0,0,0.85);
|
||
font-family: 'Courier New', monospace;
|
||
}
|
||
#foodOverlay.visible { display: flex; }
|
||
#foodOverlay .food-box {
|
||
background: #000; border: 2px solid #00ff00;
|
||
padding: 2rem 3rem; text-align: center; border-radius: 4px;
|
||
}
|
||
#foodOverlay .food-title {
|
||
color: #00ff00; font-size: 1.2rem; margin-bottom: 1.5rem;
|
||
}
|
||
#foodOverlay .food-btn {
|
||
display: block; width: 100%;
|
||
padding: 0.8rem 2rem; margin: 0.5rem 0;
|
||
background: #001100; color: #00ff00;
|
||
border: 2px solid #00ff00; cursor: pointer;
|
||
font-family: 'Courier New', monospace; font-size: 1rem;
|
||
letter-spacing: 2px; transition: background 0.2s ease;
|
||
}
|
||
#foodOverlay .food-btn:hover { background: #003300; }
|
||
#foodOverlay .food-close {
|
||
margin-top: 1rem; background: none; border: none;
|
||
color: #007700; cursor: pointer;
|
||
font-family: 'Courier New', monospace; font-size: 0.85rem;
|
||
}
|
||
#foodOverlay .food-close:hover { color: #00ff00; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<canvas id="matrixCanvas"></canvas>
|
||
|
||
<div id="textContainer">
|
||
<div class="typewriter-line" id="line1"></div>
|
||
<div class="typewriter-line" id="line2"></div>
|
||
<div class="typewriter-line" id="line3"></div>
|
||
</div>
|
||
|
||
<button id="followBtn">FOLLOW THEM</button>
|
||
|
||
<div id="scene2" class="scene">
|
||
<div id="scene2Lines">
|
||
<div id="scene2Line1">
|
||
<span id="scene2Message"></span>
|
||
<span id="scene2Cursor"></span>
|
||
</div>
|
||
<div id="scene2Line2">
|
||
<span id="scene2Message2"></span>
|
||
<span id="scene2Cursor2"></span>
|
||
</div>
|
||
</div>
|
||
<button id="whatIsLabBtn">WHAT IS LAB 484?</button>
|
||
</div>
|
||
|
||
<div id="scene3" class="scene">
|
||
<div id="scene3Title">LAB 484</div>
|
||
<div id="scene3Text"></div>
|
||
<div id="scene3ChoiceRow">
|
||
<button class="scene3ChoiceBtn" id="yourMoneyBtn">YOUR MONEY</button>
|
||
<button class="scene3ChoiceBtn" id="yourTechBtn">YOUR TECH</button>
|
||
<button class="scene3ChoiceBtn" id="yourFoodBtn">YOUR FOOD</button>
|
||
<button class="scene3ChoiceBtn" id="yourHealthBtn">YOUR HEALTH</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Scene 4 sub-scenes -->
|
||
<div id="scene4a" class="scene scene4sub">
|
||
<div class="s4tl"></div>
|
||
<div class="scene4text" id="s4aText"></div>
|
||
<div class="s4visual" id="s4aVisual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources4a">SOURCES</button>
|
||
<button class="btnNext" id="next4a">NEXT</button>
|
||
</div>
|
||
</div>
|
||
<div id="scene4b" class="scene scene4sub">
|
||
<div class="s4tl"></div>
|
||
<div class="scene4text" id="s4bText"></div>
|
||
<div class="s4visual" id="s4bVisual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources4b">SOURCES</button>
|
||
<button class="btnNext" id="next4b">NEXT</button>
|
||
</div>
|
||
</div>
|
||
<div id="scene4c" class="scene scene4sub">
|
||
<div class="s4tl"></div>
|
||
<div class="scene4text" id="s4cText"></div>
|
||
<div class="s4visual" id="s4cVisual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources4c">SOURCES</button>
|
||
<button class="btnNext" id="next4c">NEXT</button>
|
||
</div>
|
||
</div>
|
||
<div id="scene4d" class="scene scene4sub">
|
||
<div class="s4tl"></div>
|
||
<div class="scene4text" id="s4dText"></div>
|
||
<div class="s4visual" id="s4dVisual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources4d">SOURCES</button>
|
||
<button class="btnNext" id="next4d">NEXT</button>
|
||
</div>
|
||
</div>
|
||
<div id="scene4e" class="scene scene4sub">
|
||
<div class="s4tl"></div>
|
||
<div class="scene4text" id="s4eText"></div>
|
||
<div class="s4visual" id="s4eVisual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources4e">SOURCES</button>
|
||
<button class="btnNext" id="next4e">NEXT</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="scene5" class="scene">
|
||
<div class="scene5text" id="s5Text"></div>
|
||
<div class="s5visual" id="s5Visual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources5">SOURCES</button>
|
||
<button class="btnNext" id="returnFromScene5">RETURN</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="scene6" class="scene" style="flex-direction:column;">
|
||
<div id="s6TechHub">
|
||
<div class="hub-title">TECHNOLOGY</div>
|
||
<div class="hub-subtitle" id="hubSubtitle">CHOOSE A CATEGORY TO COMPARE</div>
|
||
<div class="hub-row" id="hubRow0">
|
||
<button class="hub-btn" id="goDesktopTech">DESKTOP</button>
|
||
</div>
|
||
<div class="hub-row" id="hubRow1">
|
||
<button class="hub-btn" id="goMobileTech">MOBILE</button>
|
||
</div>
|
||
<div class="hub-row" id="hubRow2">
|
||
<button class="hub-btn" id="goInternetTech">INTERNET</button>
|
||
</div>
|
||
<button class="hub-btn hub-return" id="returnFromTechHub">RETURN</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="scene7" class="scene" style="flex-direction:column;">
|
||
<div class="scene7text" id="s7Text"></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>
|
||
</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 class="scene8text" id="s8Text"></div>
|
||
<div class="s8canvas" id="s8Canvas">
|
||
<canvas id="phoneCanvas" width="800" height="320"></canvas>
|
||
<div class="mesh-status" id="phoneStatus">CLICK A TAB TO COMPARE OS SECURITY</div>
|
||
</div>
|
||
<div id="s8BtnRow">
|
||
<button class="btnNext" id="nextFromScene8">SEE THE RISK</button>
|
||
<button class="btnNext" id="returnFromScene8">RETURN</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="scene8b" class="scene" style="flex-direction:column;">
|
||
<div class="scene8text" id="s8bText"></div>
|
||
<div class="s8bcanvas" id="s8bCanvas">
|
||
<canvas id="exfilCanvas" width="800" height="360"></canvas>
|
||
<div class="exfil-counter" id="exfilCounter">DATA VALUE EXPOSED: $0/yr</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>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sourcesFromScene8b">SOURCES</button>
|
||
<button class="btnNext" id="returnFromScene8b">RETURN</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="scene9" class="scene" style="flex-direction:column;">
|
||
<div class="scene8text" id="s9Text"></div>
|
||
<div class="s9canvas" id="s9Canvas">
|
||
<canvas id="meshCanvas" width="800" height="320"></canvas>
|
||
<div class="mesh-legend">
|
||
<span class="legend-item"><span class="legend-dot online"></span> ONLINE</span>
|
||
<span class="legend-item"><span class="legend-dot offline"></span> OFFLINE</span>
|
||
<span class="legend-item"><span class="legend-dot packet"></span> PACKET</span>
|
||
</div>
|
||
<div class="mesh-status" id="meshStatus">CLICK ANY NODE TO SEE HOW MESH NETWORKS REROUTE WHEN A NODE GOES OFFLINE</div>
|
||
</div>
|
||
<button class="btnNext" id="returnFromScene9">RETURN</button>
|
||
</div>
|
||
|
||
<div id="foodOverlay">
|
||
<div class="food-box">
|
||
<div class="food-title">CHOOSE A SITE</div>
|
||
<button class="food-btn" id="foodVimeo">SIGNAL ELSEWHERE — VIMEO</button>
|
||
<button class="food-btn" id="foodKitchen">484.KITCHEN</button>
|
||
<button class="food-close" id="foodClose">CANCEL</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Health scenes (10a-10e timeline, 11 summary) -->
|
||
<div id="scene10a" class="scene scene4sub">
|
||
<div class="s4tl"></div>
|
||
<div class="scene4text" id="s10aText"></div>
|
||
<div class="s4visual" id="s10aVisual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources10a">SOURCES</button>
|
||
<button class="btnNext" id="next10a">NEXT</button>
|
||
</div>
|
||
</div>
|
||
<div id="scene10b" class="scene scene4sub">
|
||
<div class="s4tl"></div>
|
||
<div class="scene4text" id="s10bText"></div>
|
||
<div class="s4visual" id="s10bVisual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources10b">SOURCES</button>
|
||
<button class="btnNext" id="next10b">NEXT</button>
|
||
</div>
|
||
</div>
|
||
<div id="scene10c" class="scene scene4sub">
|
||
<div class="s4tl"></div>
|
||
<div class="scene4text" id="s10cText"></div>
|
||
<div class="s4visual" id="s10cVisual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources10c">SOURCES</button>
|
||
<button class="btnNext" id="next10c">NEXT</button>
|
||
</div>
|
||
</div>
|
||
<div id="scene10d" class="scene scene4sub">
|
||
<div class="s4tl"></div>
|
||
<div class="scene4text" id="s10dText"></div>
|
||
<div class="s4visual" id="s10dVisual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources10d">SOURCES</button>
|
||
<button class="btnNext" id="next10d">NEXT</button>
|
||
</div>
|
||
</div>
|
||
<div id="scene10e" class="scene scene4sub">
|
||
<div class="s4tl"></div>
|
||
<div class="scene4text" id="s10eText"></div>
|
||
<div class="s4visual" id="s10eVisual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources10e">SOURCES</button>
|
||
<button class="btnNext" id="next10e">NEXT</button>
|
||
</div>
|
||
</div>
|
||
<div id="scene11" class="scene">
|
||
<div class="scene5text" id="s11Text"></div>
|
||
<div class="s5visual" id="s11Visual"></div>
|
||
<div class="btn-row">
|
||
<button class="btnNext" id="sources11">SOURCES</button>
|
||
<button class="btnNext" id="returnFromScene11">RETURN</button>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Testing shortcuts state
|
||
let skipAnimations = false;
|
||
let scene3TypewriterTimeouts = [];
|
||
|
||
// Canvas setup for Matrix rain
|
||
const canvas = document.getElementById('matrixCanvas');
|
||
const ctx = canvas.getContext('2d');
|
||
|
||
function resizeCanvas() {
|
||
canvas.width = window.innerWidth;
|
||
canvas.height = window.innerHeight;
|
||
}
|
||
resizeCanvas();
|
||
window.addEventListener('resize', resizeCanvas);
|
||
|
||
// Matrix rain configuration
|
||
const fontSize = 14;
|
||
let columns = Math.floor(canvas.width / fontSize);
|
||
let drops = [];
|
||
const chars = '0123456789@#$%^&*()';
|
||
const rainDuration = 5000; // 5 seconds
|
||
let rainActive = false;
|
||
let rainStartTime = null;
|
||
|
||
// CRT flicker effect
|
||
function crtFlicker() {
|
||
let flickerCount = 0;
|
||
const maxFlickers = 3;
|
||
const flickerInterval = setInterval(() => {
|
||
ctx.fillStyle = flickerCount % 2 === 0 ? 'rgba(255,255,255,0.15)' : 'rgba(0,0,0,1)';
|
||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||
flickerCount++;
|
||
if (flickerCount >= maxFlickers * 2) {
|
||
clearInterval(flickerInterval);
|
||
ctx.fillStyle = '#000';
|
||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||
startMatrixRain();
|
||
}
|
||
}, 100);
|
||
}
|
||
|
||
// Start Matrix rain animation
|
||
function startMatrixRain() {
|
||
rainActive = true;
|
||
rainStartTime = Date.now();
|
||
columns = Math.floor(canvas.width / fontSize);
|
||
drops = Array(columns).fill(0).map(() => Math.floor(Math.random() * canvas.height / fontSize));
|
||
drawMatrix();
|
||
}
|
||
|
||
// Draw Matrix rain frame
|
||
function drawMatrix() {
|
||
if (!rainActive) return;
|
||
|
||
// Create trail effect
|
||
ctx.fillStyle = 'rgba(0,0,0,0.05)';
|
||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||
ctx.fillStyle = '#00ff00';
|
||
ctx.font = fontSize + 'px Courier New, monospace';
|
||
|
||
for (let i = 0; i < columns; i++) {
|
||
const x = i * fontSize;
|
||
const y = drops[i] * fontSize;
|
||
|
||
// Chance to render "484" as a horizontal string in this column
|
||
if (Math.random() < 0.003) {
|
||
ctx.fillText('484', x, y);
|
||
} else {
|
||
const text = chars[Math.floor(Math.random() * chars.length)];
|
||
ctx.fillText(text, x, y);
|
||
}
|
||
|
||
// Reset drop when it goes off screen
|
||
if (y > canvas.height && Math.random() > 0.975) {
|
||
drops[i] = 0;
|
||
}
|
||
drops[i] += 0.5;
|
||
}
|
||
|
||
// End rain after duration
|
||
if (Date.now() - rainStartTime > rainDuration) {
|
||
fadeRainToBackground();
|
||
rainActive = false;
|
||
} else {
|
||
requestAnimationFrame(drawMatrix);
|
||
}
|
||
}
|
||
|
||
// Fade rain to background
|
||
function fadeRainToBackground() {
|
||
const canvasElem = document.getElementById('matrixCanvas');
|
||
let opacity = 1;
|
||
const fadeInterval = setInterval(() => {
|
||
opacity -= 0.02;
|
||
if (opacity <= 0.15) {
|
||
opacity = 0.15;
|
||
clearInterval(fadeInterval);
|
||
document.getElementById('textContainer').style.visibility = 'visible';
|
||
typewriter();
|
||
}
|
||
canvasElem.style.opacity = opacity;
|
||
}, 16);
|
||
}
|
||
|
||
// Reusable typewriter function with custom delays
|
||
function typewriterLines(lines, targetElem, onComplete, charDelay, lineDelay, endCharDelay) {
|
||
charDelay = charDelay || 60;
|
||
lineDelay = lineDelay || 500;
|
||
let currentLine = 0;
|
||
let currentChar = 0;
|
||
let totalChars = 0;
|
||
let charsTyped = 0;
|
||
|
||
// Calculate total characters if using accelerating speed
|
||
if (endCharDelay !== null) {
|
||
totalChars = 0;
|
||
for (let i = 0; i < lines.length; i++) {
|
||
totalChars += lines[i].length;
|
||
}
|
||
}
|
||
|
||
function getDelay() {
|
||
if (endCharDelay === null || totalChars === 0) return charDelay;
|
||
const progress = charsTyped / totalChars;
|
||
return charDelay + (endCharDelay - charDelay) * progress;
|
||
}
|
||
|
||
function tick() {
|
||
if (skipAnimations) {
|
||
let remainingText = '';
|
||
for (let i = currentLine; i < lines.length; i++) {
|
||
remainingText += lines[i];
|
||
}
|
||
targetElem.textContent = remainingText;
|
||
onComplete && onComplete();
|
||
return;
|
||
}
|
||
|
||
if (currentLine >= lines.length) {
|
||
onComplete && 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",
|
||
"THE SYNCHRONICITIES YOU ARE EXPERIENCING HAVE ALWAYS BEEN THERE",
|
||
"THE ONLY THING THAT HAS CHANGED IS YOUR AWARENESS OF THEM"
|
||
];
|
||
let scene1LineIndex = 0;
|
||
let scene1Timeouts = [];
|
||
|
||
function typewriter() {
|
||
if (scene1LineIndex >= scene1lines.length) {
|
||
showButton();
|
||
return;
|
||
}
|
||
|
||
const lineElem = document.getElementById('line' + (scene1LineIndex + 1));
|
||
lineElem.style.visibility = 'visible';
|
||
const lineText = scene1lines[scene1LineIndex];
|
||
let charIndex = 0;
|
||
|
||
function typeChar() {
|
||
if (charIndex < lineText.length) {
|
||
lineElem.textContent += lineText[charIndex];
|
||
charIndex++;
|
||
const t = setTimeout(typeChar, 60);
|
||
scene1Timeouts.push(t);
|
||
} else {
|
||
scene1LineIndex++;
|
||
const t = setTimeout(typewriter, 500);
|
||
scene1Timeouts.push(t);
|
||
}
|
||
}
|
||
typeChar();
|
||
}
|
||
|
||
function skipScene1() {
|
||
scene1Timeouts.forEach(t => clearTimeout(t));
|
||
scene1Timeouts = [];
|
||
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
|
||
function showButton() {
|
||
const btn = document.getElementById('followBtn');
|
||
btn.style.visibility = 'visible';
|
||
let opacity = 0;
|
||
const fadeIn = setInterval(() => {
|
||
opacity += 0.05;
|
||
if (opacity >= 1) {
|
||
opacity = 1;
|
||
clearInterval(fadeIn);
|
||
btn.style.pointerEvents = 'auto';
|
||
}
|
||
btn.style.opacity = opacity;
|
||
}, 30);
|
||
}
|
||
|
||
// Scene transition functions
|
||
function transitionToScene2() {
|
||
const canvas = document.getElementById('matrixCanvas');
|
||
const textContainer = document.getElementById('textContainer');
|
||
const btn = document.getElementById('followBtn');
|
||
const scene2 = document.getElementById('scene2');
|
||
|
||
let opacity = 1;
|
||
const fadeOut = setInterval(() => {
|
||
opacity -= 0.05;
|
||
if (opacity <= 0) {
|
||
opacity = 0;
|
||
clearInterval(fadeOut);
|
||
canvas.style.display = 'none';
|
||
textContainer.style.display = 'none';
|
||
btn.style.display = 'none';
|
||
loadScene2(scene2);
|
||
}
|
||
canvas.style.opacity = opacity;
|
||
textContainer.style.opacity = opacity;
|
||
btn.style.opacity = opacity;
|
||
}, 30);
|
||
}
|
||
|
||
// Scene 2 loader: calm typing sequence
|
||
function blinkCursor(cursor, times, callback) {
|
||
cursor.style.display = 'inline-block';
|
||
cursor.style.opacity = '1';
|
||
let count = 0;
|
||
let visible = true;
|
||
const interval = setInterval(() => {
|
||
visible = !visible;
|
||
cursor.style.opacity = visible ? '1' : '0';
|
||
count++;
|
||
if (count >= times * 2) {
|
||
clearInterval(interval);
|
||
cursor.style.display = 'none';
|
||
callback && callback();
|
||
}
|
||
}, 500);
|
||
}
|
||
|
||
function typeCalmly(elem, text, callback, minDelay, maxDelay, timeoutArray) {
|
||
let i = 0;
|
||
const total = text.length;
|
||
|
||
function typeChar() {
|
||
if (i >= total) {
|
||
callback && callback();
|
||
return;
|
||
}
|
||
elem.textContent += text[i];
|
||
i++;
|
||
const progress = i / total;
|
||
const dMin = minDelay || 35;
|
||
const dMax = maxDelay || 65;
|
||
const delay = dMin + progress * progress * (dMax - dMin);
|
||
const id = setTimeout(typeChar, delay);
|
||
timeoutArray && timeoutArray.push(id);
|
||
}
|
||
typeChar();
|
||
}
|
||
|
||
function typeHtmlCalmly(elem, html, callback, minDelay, maxDelay, timeoutArray) {
|
||
let i = 0;
|
||
const total = html.length;
|
||
function typeChar() {
|
||
if (i >= total) { callback && callback(); return; }
|
||
elem.innerHTML += html[i];
|
||
i++;
|
||
const progress = i / total;
|
||
const dMin = minDelay || 35;
|
||
const dMax = maxDelay || 65;
|
||
const delay = dMin + progress * progress * (dMax - dMin);
|
||
const id = setTimeout(typeChar, delay);
|
||
timeoutArray && timeoutArray.push(id);
|
||
}
|
||
typeChar();
|
||
}
|
||
|
||
function loadScene2(sceneElem) {
|
||
s2c.forEach(t => clearTimeout(t));
|
||
s2c = [];
|
||
sceneElem.style.display = 'flex';
|
||
const linesContainer = document.getElementById('scene2Lines');
|
||
const line1 = document.getElementById('scene2Line1');
|
||
const line2 = document.getElementById('scene2Line2');
|
||
const message = document.getElementById('scene2Message');
|
||
const message2 = document.getElementById('scene2Message2');
|
||
const cursor = document.getElementById('scene2Cursor');
|
||
const cursor2 = document.getElementById('scene2Cursor2');
|
||
const btn = document.getElementById('whatIsLabBtn');
|
||
message.textContent = '';
|
||
message2.textContent = '';
|
||
|
||
let opacity = 0;
|
||
const fadeIn = setInterval(() => {
|
||
if (sceneElem.style.display !== 'flex' || btn.style.visibility === 'visible') {
|
||
clearInterval(fadeIn);
|
||
return;
|
||
}
|
||
opacity += 0.05;
|
||
if (opacity >= 1) {
|
||
opacity = 1;
|
||
clearInterval(fadeIn);
|
||
|
||
linesContainer.style.display = 'flex';
|
||
line1.style.visibility = 'visible';
|
||
|
||
blinkCursor(cursor, 3, () => {
|
||
typeCalmly(message, "...AND THAT AWARENESS HAS LED YOU HERE...", () => {
|
||
cursor.style.display = 'none';
|
||
line2.style.display = 'flex';
|
||
|
||
blinkCursor(cursor2, 1, () => {
|
||
typeCalmly(message2, "TO LAB 484", () => {
|
||
setTimeout(() => {
|
||
btn.style.visibility = 'visible';
|
||
let btnOpacity = 0;
|
||
const btnFadeIn = setInterval(() => {
|
||
btnOpacity += 0.05;
|
||
if (btnOpacity >= 1) {
|
||
btnOpacity = 1;
|
||
clearInterval(btnFadeIn);
|
||
btn.style.pointerEvents = 'auto';
|
||
}
|
||
btn.style.opacity = btnOpacity;
|
||
}, 30);
|
||
}, 1000);
|
||
}, undefined, undefined, s2c);
|
||
});
|
||
}, undefined, undefined, s2c);
|
||
});
|
||
}
|
||
sceneElem.style.opacity = opacity;
|
||
}, 30);
|
||
}
|
||
|
||
// Scene transition helper
|
||
function transitionToScene(fromId, loader, toId) {
|
||
const from = document.getElementById(fromId);
|
||
from.style.display = 'none';
|
||
const to = document.getElementById(toId);
|
||
loader(to);
|
||
}
|
||
|
||
// Scene 3 loader
|
||
function loadScene3(sceneElem) {
|
||
scene3TypewriterTimeouts.forEach(t => clearTimeout(t));
|
||
scene3TypewriterTimeouts = [];
|
||
sceneElem.style.display = 'flex';
|
||
const title = document.getElementById('scene3Title');
|
||
const textContainer = document.getElementById('scene3Text');
|
||
textContainer.textContent = '';
|
||
|
||
let opacity = 0;
|
||
const fadeIn = setInterval(() => {
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('scene3ChoiceRow').style.display === 'flex') {
|
||
clearInterval(fadeIn);
|
||
return;
|
||
}
|
||
opacity += 0.05;
|
||
if (opacity >= 1) {
|
||
opacity = 1;
|
||
clearInterval(fadeIn);
|
||
|
||
setTimeout(() => {
|
||
title.classList.add('visible');
|
||
}, 300);
|
||
|
||
const tMain = setTimeout(() => {
|
||
const line1 = document.createElement('div');
|
||
line1.textContent = "IS AN INCUBATOR THAT HAS MANY DECENTRALIZED STARTUPS UNDERNEATH IT";
|
||
line1.style.cssText = 'opacity:0;transition:opacity 4s ease;';
|
||
textContainer.appendChild(line1);
|
||
const t1 = setTimeout(() => line1.style.opacity = '1', 50);
|
||
scene3TypewriterTimeouts.push(t1);
|
||
|
||
const tLine2 = setTimeout(() => {
|
||
const line2 = document.createElement('div');
|
||
line2.textContent = "WE BELIEVE EVERYTHING SHOULD BE DECENTRALIZED";
|
||
line2.style.cssText = 'opacity:0;transition:opacity 1.5s ease;margin-top:11rem;margin-bottom:2rem;display:flex;justify-content:center;width:100%;';
|
||
textContainer.appendChild(line2);
|
||
const t2 = setTimeout(() => line2.style.opacity = '1', 50);
|
||
scene3TypewriterTimeouts.push(t2);
|
||
}, 3000);
|
||
scene3TypewriterTimeouts.push(tLine2);
|
||
|
||
const row = document.getElementById('scene3ChoiceRow');
|
||
row.style.display = 'flex';
|
||
const btns = row.querySelectorAll('.scene3ChoiceBtn');
|
||
btns.forEach((btn, i) => {
|
||
const tBtn = setTimeout(() => {
|
||
btn.style.opacity = '1';
|
||
btn.style.pointerEvents = 'auto';
|
||
}, i * 200 + 3500);
|
||
scene3TypewriterTimeouts.push(tBtn);
|
||
});
|
||
}, 600);
|
||
scene3TypewriterTimeouts.push(tMain);
|
||
}
|
||
sceneElem.style.opacity = opacity;
|
||
}, 30);
|
||
}
|
||
|
||
// Scene 4 helpers
|
||
function buildTimeline(tlElem, activeIdx) {
|
||
const years = ['1900', '1933', '1934', '1971', '2009'];
|
||
tlElem.innerHTML = '';
|
||
years.forEach((y, i) => {
|
||
const span = document.createElement('span');
|
||
span.className = 'tl-year' + (i < activeIdx ? ' dim' : '') + (i === activeIdx ? ' active' : '');
|
||
span.textContent = y;
|
||
tlElem.appendChild(span);
|
||
});
|
||
tlElem.classList.add('visible');
|
||
}
|
||
|
||
function buildHTimeline(tlElem, activeIdx) {
|
||
const years = ['1910', '1938', '1965', '1973', '2010'];
|
||
tlElem.innerHTML = '';
|
||
years.forEach((y, i) => {
|
||
const span = document.createElement('span');
|
||
span.className = 'tl-year' + (i < activeIdx ? ' dim' : '') + (i === activeIdx ? ' active' : '');
|
||
span.textContent = y;
|
||
tlElem.appendChild(span);
|
||
});
|
||
tlElem.classList.add('visible');
|
||
}
|
||
|
||
function showNextBtn(id) {
|
||
const btn = document.getElementById(id);
|
||
btn.style.visibility = 'visible';
|
||
let o = 0;
|
||
const fi = setInterval(() => {
|
||
o += 0.05; if (o >= 1) { o = 1; clearInterval(fi); btn.style.pointerEvents = 'auto'; }
|
||
btn.style.opacity = o;
|
||
}, 30);
|
||
}
|
||
|
||
// Scene 4a — HOOK + 1900 Gold Standard
|
||
function loadScene4a(sceneElem) {
|
||
s4c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=sceneElem.querySelector('.scene4text');
|
||
const vis=sceneElem.querySelector('.s4visual');
|
||
const tl=sceneElem.querySelector('.s4tl');
|
||
txt.innerHTML='';
|
||
vis.className='s4visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('next4a').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
buildTimeline(tl,0);
|
||
typeHtmlCalmly(txt,"IMAGINE THE GOVERNMENT SHOWED UP AT YOUR DOOR AND DEMANDED YOUR SAVINGS.",()=>{
|
||
const tWait=setTimeout(()=>{
|
||
typeHtmlCalmly(txt,"\n\nTHAT'S NOT HYPOTHETICAL — IT HAPPENED IN 1933.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"IN 1900, THE GOLD STANDARD ACT WAS PASSED. EVERY DOLLAR WAS BACKED BY GOLD — REAL, TANGIBLE, TRUSTWORTHY. ",()=>{
|
||
const span=document.createElement('span');
|
||
txt.appendChild(span);
|
||
typeHtmlCalmly(span,"THE GOLD STANDARD ACT OF 1900",()=>{
|
||
const link=document.createElement('a');
|
||
link.href='https://www.gold.org/sites/default/files/documents/1900mar14.pdf';
|
||
link.target='_blank';
|
||
link.textContent=span.textContent;
|
||
link.style.cssText='text-decoration:underline;font-weight:bold;color:#00ff00';
|
||
span.replaceWith(link);
|
||
showNextBtn('next4a');showNextBtn('sources4a');
|
||
},undefined,undefined,s4c);
|
||
},undefined,undefined,s4c);
|
||
},1500);
|
||
s4c.push(t1);
|
||
},undefined,undefined,s4c);
|
||
},1000);
|
||
s4c.push(tWait);
|
||
},undefined,undefined,s4c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Scene 4b — 1933 ORDER 6102
|
||
function loadScene4b(sceneElem) {
|
||
s4c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=sceneElem.querySelector('.scene4text');
|
||
const vis=sceneElem.querySelector('.s4visual');
|
||
const tl=sceneElem.querySelector('.s4tl');
|
||
txt.innerHTML='';
|
||
vis.className='s4visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('next4b').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
buildTimeline(tl,1);
|
||
typeHtmlCalmly(txt,"ON APRIL 5, 1933, ",()=>{
|
||
const link=document.createElement('a');
|
||
link.href='https://www.usmoneyreserve.com/resources/videos/transcripts/executive-order-6102-did-you-know/';
|
||
link.target='_blank';
|
||
link.textContent='ORDER 6102';
|
||
link.style.cssText='text-decoration:underline;font-weight:bold;color:#00ff00';
|
||
txt.appendChild(link);
|
||
typeHtmlCalmly(txt," MADE IT A CRIME TO HOLD GOLD.",()=>{
|
||
typeHtmlCalmly(txt,"\n\nCITIZENS WERE FORCED TO TURN IN THEIR GOLD IN EXCHANGE FOR PAPER DOLLARS.",()=>{
|
||
showNextBtn('next4b');showNextBtn('sources4b');
|
||
},undefined,undefined,s4c);
|
||
},undefined,undefined,s4c);
|
||
},undefined,undefined,s4c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Scene 4c — 1934 Gold Reserve Act + 69%
|
||
function loadScene4c(sceneElem) {
|
||
s4c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=sceneElem.querySelector('.scene4text');
|
||
const vis=sceneElem.querySelector('.s4visual');
|
||
const tl=sceneElem.querySelector('.s4tl');
|
||
txt.innerHTML='';
|
||
vis.className='s4visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('next4c').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
buildTimeline(tl,2);
|
||
typeHtmlCalmly(txt,"AFTER FORCING PEOPLE TO TURN IN THEIR GOLD, THE GOVERNMENT PASSED THE ",()=>{
|
||
const link=document.createElement('a');
|
||
link.href='https://www.federalreservehistory.org/essays/gold-reserve-act';
|
||
link.target='_blank';
|
||
link.textContent='THE 1934 GOLD RESERVE ACT';
|
||
link.style.cssText='text-decoration:underline;font-weight:bold;color:#00ff00';
|
||
txt.appendChild(link);
|
||
typeHtmlCalmly(txt," AND GAVE THE U.S. TREASURY CONTROL OF THE GOLD.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"PEOPLE WERE PAID $20.67/OZ. THE GOVT THEN REVALUED GOLD TO $35/OZ.",()=>{
|
||
const t2=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
vis.innerHTML='<div class="callout-box">⚠ $20.67/OZ → $35/OZ = 69% STOLEN OVERNIGHT ⚠</div>';
|
||
vis.classList.add('visible');
|
||
showNextBtn('next4c');showNextBtn('sources4c');
|
||
},800);
|
||
s4c.push(t2);
|
||
},undefined,undefined,s4c);
|
||
},1200);
|
||
s4c.push(t1);
|
||
},undefined,undefined,s4c);
|
||
},undefined,undefined,s4c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Scene 4d — 1971 Nixon shock + coin visual
|
||
function loadScene4d(sceneElem) {
|
||
s4c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=sceneElem.querySelector('.scene4text');
|
||
const vis=sceneElem.querySelector('.s4visual');
|
||
const tl=sceneElem.querySelector('.s4tl');
|
||
txt.innerHTML='';
|
||
vis.className='s4visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('next4d').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
buildTimeline(tl,3);
|
||
typeHtmlCalmly(txt,"THE PAPER DOLLAR COULD STILL BE EXCHANGED FOR GOLD, BUT ON ",()=>{
|
||
const link=document.createElement('a');
|
||
link.href='https://www.federalreservehistory.org/essays/gold-convertibility-ends';
|
||
link.target='_blank';
|
||
link.textContent='1971, PRESIDENT NIXON REMOVED THAT OPTION';
|
||
link.style.cssText='text-decoration:underline;font-weight:bold;color:#00ff00';
|
||
txt.appendChild(link);
|
||
typeHtmlCalmly(txt,", THE PRICE OF GOLD SURGED TO $835-850/OZ.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"THE DOLLAR LOST 96% OF ITS PURCHASING POWER AGAINST REAL MONEY.",()=>{
|
||
const t2=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
let html='<div style="text-align:center;font-size:0.8rem;color:#007700;margin-bottom:0.5rem;">VALUE OF $1 SINCE 1971</div><div class="coin-grid">';
|
||
for(let i=0;i<100;i++){
|
||
const c=i<4?'gold':'';
|
||
html+='<div class="coin '+c+'"></div>';
|
||
}
|
||
html+='</div><div style="text-align:center;margin-top:0.5rem;font-size:0.75rem;color:#00ff00;">~96% PURCHASING POWER LOST</div>';
|
||
vis.innerHTML=html;
|
||
vis.classList.add('visible');
|
||
showNextBtn('next4d');showNextBtn('sources4d');
|
||
},800);
|
||
s4c.push(t2);
|
||
},undefined,undefined,s4c);
|
||
},1200);
|
||
s4c.push(t1);
|
||
},undefined,undefined,s4c);
|
||
},undefined,undefined,s4c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Scene 4e — Bitcoin closing + comparison table + punch cards
|
||
function loadScene4e(sceneElem) {
|
||
s4c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=sceneElem.querySelector('.scene4text');
|
||
const vis=sceneElem.querySelector('.s4visual');
|
||
const tl=sceneElem.querySelector('.s4tl');
|
||
txt.innerHTML='';
|
||
vis.className='s4visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('next4e').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
buildTimeline(tl,4);
|
||
typeHtmlCalmly(txt,"BITCOIN HAS BEEN CALLED ",()=>{
|
||
const link=document.createElement('a');
|
||
link.href='https://www.forbes.com/sites/digital-assets/2024/12/08/us-treasury-names-bitcoin-digital-gold-after-price-explosion/';
|
||
link.target='_blank';
|
||
link.textContent='DIGITAL GOLD';
|
||
link.style.cssText='text-decoration:underline;font-weight:bold;color:#00ff00';
|
||
txt.appendChild(link);
|
||
typeHtmlCalmly(txt,". BUT UNLIKE GOLD, NO ONE CAN TOUCH THIS.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
vis.innerHTML=
|
||
'<table class="comp-table"><tr><th></th><th>GOLD</th><th>BITCOIN</th></tr>'
|
||
+'<tr><td>CONFISCATABLE?</td><td class="yes">✅ YES (1933)</td><td class="no">❌ NO</td></tr>'
|
||
+'<tr><td>PRINTABLE?</td><td class="no">❌ NO</td><td class="no">❌ NO</td></tr>'
|
||
+'<tr><td>UNCENSORABLE?</td><td class="no">❌ NO</td><td class="yes">✅ YES</td></tr>'
|
||
+'<tr><td>SUPPLY CAP?</td><td class="no">❌ NO</td><td class="yes">✅ 21M</td></tr>'
|
||
+'<tr><td>TRUST MODEL</td><td>GOVERNMENT</td><td>CODE</td></tr>'
|
||
+'</table>'
|
||
+'<div class="punch-row">'
|
||
+'<div class="punch-card"><span class="punch-icon">🚫</span><span class="punch-text">NO PRESIDENT<br>CAN BAN IT</span></div>'
|
||
+'<div class="punch-card"><span class="punch-icon">🚫</span><span class="punch-text">NO CONGRESS<br>CAN INFLATE IT</span></div>'
|
||
+'<div class="punch-card"><span class="punch-icon">🚫</span><span class="punch-text">NO BANK<br>CAN FREEZE IT</span></div>'
|
||
+'</div>';
|
||
vis.classList.add('visible');
|
||
showNextBtn('next4e');showNextBtn('sources4e');
|
||
},1200);
|
||
s4c.push(t1);
|
||
},undefined,undefined,s4c);
|
||
},undefined,undefined,s4c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Scene 5 — BTC vs. Altcoins comparison
|
||
function loadScene5(sceneElem) {
|
||
s5c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=document.getElementById('s5Text');
|
||
const vis=document.getElementById('s5Visual');
|
||
txt.innerHTML='';
|
||
vis.className='s5visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('returnFromScene5').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
typeCalmly(txt,"BITCOIN HAS NO TRUE COMPETITORS AS SOUND MONEY.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
vis.classList.add('visible');
|
||
buildS5Table(vis);
|
||
typeCalmly(txt,"BUT SEVERAL COINS COMPETE IN DIFFERENT NICHES — PRIVACY, SPEED, PROGRAMMABILITY, OR STORE-OF-VALUE NARRATIVES.",()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeCalmly(txt,"NONE POSSESS BITCOIN'S FULL SET OF PROPERTIES.",()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeCalmly(txt,"THE NETWORK EFFECT IS INSURMOUNTABLE.",()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeCalmly(txt,"HERE IS THE HONEST COMPARISON.",()=>{
|
||
const t6=setTimeout(()=>{
|
||
document.getElementById('returnFromScene5').style.cssText='';
|
||
showNextBtn('returnFromScene5');
|
||
document.getElementById('sources5').style.cssText='';
|
||
showNextBtn('sources5');
|
||
},400);
|
||
s5c.push(t6);
|
||
},8,20,s5c);
|
||
},8,20,s5c);
|
||
},8,20,s5c);
|
||
},8,20,s5c);
|
||
},300);
|
||
s5c.push(t1);
|
||
},8,20,s5c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
function buildS5Table(vis) {
|
||
const rows=[
|
||
['NICHE','<span class="nickname">SOUND MONEY</span>','PROGRAMMABILITY','PRIVACY','PAYMENTS','SPEED'],
|
||
['DECENTRALIZED?','✅ YES','⚠️ PARTIAL','✅ YES','❌ RIPPLE LABS','❌ VC/FOUNDATION'],
|
||
['FAIR LAUNCH?','✅ YES','❌ 72M PREMINE','✅ YES','❌ 100% PREMINE','❌ PREMINE'],
|
||
['SUPPLY CAP','✅ 21M','❌ NO CAP','❌ TAIL EMISSION','❌ NO CAP','❌ NO CAP'],
|
||
['UNCENSORABLE?','✅ YES','❌ NO','✅ YES','❌ NO','❌ NO'],
|
||
];
|
||
let html='<table class="comp-table" id="s5table"><tr><th></th><th class="btc-col">BTC</th><th>ETH</th><th>XMR</th><th>XRP</th><th>SOL</th></tr>';
|
||
for(let r=0;r<rows.length;r++){
|
||
const cells=rows[r];
|
||
html+='<tr>';
|
||
for(let c=0;c<cells.length;c++){
|
||
html+='<td'+(c===1?' class="btc-col"':'')+'>'+cells[c]+'</td>';
|
||
}
|
||
html+='</tr>';
|
||
}
|
||
html+='</table><div class="punch-row"><div class="punch-card"><span class="punch-icon">🏆</span><span class="punch-text">FIRST —<br>EVERYTHING ELSE IS A COPY</span></div><div class="punch-card"><span class="punch-icon">🔒</span><span class="punch-text">MOST SECURE —<br>MOST HASH POWER BY FAR</span></div><div class="punch-card"><span class="punch-icon">🧪</span><span class="punch-text">TRULY DECENTRALIZED —<br>NO FOUNDER, NO COMPANY, NO CEO</span></div></div>';
|
||
vis.innerHTML+=html;
|
||
}
|
||
|
||
// Scene 10a — 1910 Flexner Report
|
||
function loadScene10a(sceneElem) {
|
||
h10c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=sceneElem.querySelector('.scene4text');
|
||
const vis=sceneElem.querySelector('.s4visual');
|
||
const tl=sceneElem.querySelector('.s4tl');
|
||
txt.innerHTML='';
|
||
vis.className='s4visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('next10a').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
buildHTimeline(tl,0);
|
||
typeHtmlCalmly(txt,"IMAGINE THE GOVERNMENT DECIDED WHICH DOCTORS WERE ALLOWED TO PRACTICE — AND SHUT DOWN EVERY OTHER OPTION OVERNIGHT.",()=>{
|
||
const tWait=setTimeout(()=>{
|
||
typeHtmlCalmly(txt,"\n\nTHAT'S NOT HYPOTHETICAL — IT HAPPENED IN 1910.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"THE CARNEGIE FOUNDATION COMMISSIONED THE FLEXNER REPORT. IT EVALUATED EVERY MEDICAL SCHOOL IN AMERICA. HALF WERE SHUT DOWN — PARTICULARLY THOSE TRAINING WOMEN, BLACK DOCTORS, AND RURAL PRACTITIONERS.",()=>{
|
||
const t2=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"THE AMERICAN MEDICAL ASSOCIATION TOOK CONTROL OF MEDICAL LICENSING. MEDICINE BECAME A GATEKEPT PROFESSION.",()=>{
|
||
showNextBtn('next10a');showNextBtn('sources10a');
|
||
},undefined,undefined,h10c);
|
||
},800);
|
||
h10c.push(t2);
|
||
},undefined,undefined,h10c);
|
||
},1000);
|
||
h10c.push(t1);
|
||
},undefined,undefined,h10c);
|
||
},1000);
|
||
h10c.push(tWait);
|
||
},undefined,undefined,h10c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Scene 10b — 1938 FDA Control
|
||
function loadScene10b(sceneElem) {
|
||
h10c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=sceneElem.querySelector('.scene4text');
|
||
const vis=sceneElem.querySelector('.s4visual');
|
||
const tl=sceneElem.querySelector('.s4tl');
|
||
txt.innerHTML='';
|
||
vis.className='s4visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('next10b').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
buildHTimeline(tl,1);
|
||
typeHtmlCalmly(txt,"IN 1938, AFTER THE ELIXIR SULFANILAMIDE TRAGEDY KILLED 107 PEOPLE, THE FDA WAS GIVEN BROAD POWER TO REGULATE MEDICINE.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"THE FOOD, DRUG & COSMETIC ACT REQUIRED DRUGS TO BE PROVEN SAFE BEFORE SALE.",()=>{
|
||
const t2=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"SOUNDS REASONABLE — BUT IT ALSO MEANT NO TREATMENT COULD EXIST WITHOUT GOVERNMENT APPROVAL.",()=>{
|
||
const t3=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"THE POWER TO APPROVE IS THE POWER TO CONTROL.",()=>{
|
||
showNextBtn('next10b');showNextBtn('sources10b');
|
||
},undefined,undefined,h10c);
|
||
},800);
|
||
h10c.push(t3);
|
||
},undefined,undefined,h10c);
|
||
},800);
|
||
h10c.push(t2);
|
||
},undefined,undefined,h10c);
|
||
},1600);
|
||
h10c.push(t1);
|
||
},undefined,undefined,h10c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Scene 10c — 1965 Medicare/Medicaid cost explosion
|
||
function loadScene10c(sceneElem) {
|
||
h10c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=sceneElem.querySelector('.scene4text');
|
||
const vis=sceneElem.querySelector('.s4visual');
|
||
const tl=sceneElem.querySelector('.s4tl');
|
||
txt.innerHTML='';
|
||
vis.className='s4visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('next10c').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
buildHTimeline(tl,2);
|
||
typeHtmlCalmly(txt,"IN 1965, MEDICARE AND MEDICAID WERE CREATED. THE THIRD-PARTY PAYER SYSTEM WAS BORN.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"HEALTHCARE SPENDING WAS $41 BILLION IN 1965. BY 2022, IT REACHED $4.1 TRILLION.",()=>{
|
||
const t2=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
vis.innerHTML='<div class="callout-box">⚠ $41B → $4.1T = 100x IN 57 YEARS ⚠</div>';
|
||
vis.classList.add('visible');
|
||
showNextBtn('next10c');showNextBtn('sources10c');
|
||
},800);
|
||
h10c.push(t2);
|
||
},undefined,undefined,h10c);
|
||
},1200);
|
||
h10c.push(t1);
|
||
},undefined,undefined,h10c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Scene 10d — 1973 HMO Act
|
||
function loadScene10d(sceneElem) {
|
||
h10c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=sceneElem.querySelector('.scene4text');
|
||
const vis=sceneElem.querySelector('.s4visual');
|
||
const tl=sceneElem.querySelector('.s4tl');
|
||
txt.innerHTML='';
|
||
vis.className='s4visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('next10d').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
buildHTimeline(tl,3);
|
||
typeHtmlCalmly(txt,"IN 1973, THE HMO ACT FORMALIZED MANAGED CARE.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"YOUR DOCTOR NO LONGER WORKS FOR YOU — THEY WORK FOR THE INSURANCE COMPANY.",()=>{
|
||
const t2=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"THE DOCTOR-PATIENT RELATIONSHIP WAS REPLACED BY THE CORPORATE PROVIDER-MEMBER MODEL.",()=>{
|
||
const t3=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"YOU BECAME THE PRODUCT.",()=>{
|
||
showNextBtn('next10d');showNextBtn('sources10d');
|
||
},undefined,undefined,h10c);
|
||
},800);
|
||
h10c.push(t3);
|
||
},undefined,undefined,h10c);
|
||
},800);
|
||
h10c.push(t2);
|
||
},undefined,undefined,h10c);
|
||
},1200);
|
||
h10c.push(t1);
|
||
},undefined,undefined,h10c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Scene 10e — 2010+ Decentralized Health
|
||
function loadScene10e(sceneElem) {
|
||
h10c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=sceneElem.querySelector('.scene4text');
|
||
const vis=sceneElem.querySelector('.s4visual');
|
||
const tl=sceneElem.querySelector('.s4tl');
|
||
txt.innerHTML='';
|
||
vis.className='s4visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('next10e').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
buildHTimeline(tl,4);
|
||
typeHtmlCalmly(txt,"TODAY, A NEW KIND OF MEDICINE IS EMERGING — BIOHACKING, FUNCTIONAL MEDICINE, DIRECT-TO-CONSUMER TESTING.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"PROJECTS LIKE SYNTPROPY.INSTITUTE ARE BUILDING THE INFRASTRUCTURE FOR MEDICINE YOU CONTROL.",()=>{
|
||
const t2=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
let html='<table class="comp-table"><tr><th></th><th>TRADITIONAL</th><th>DECENTRALIZED</th></tr>';
|
||
html+='<tr><td>WHO DECIDES?</td><td>GOVERNMENT / INSURANCE</td><td>YOU + YOUR DOCTOR</td></tr>';
|
||
html+='<tr><td>ACCESS</td><td>GATEKEPT</td><td>DIRECT</td></tr>';
|
||
html+='<tr><td>DATA OWNERSHIP</td><td>THE SYSTEM</td><td>YOU</td></tr>';
|
||
html+='<tr><td>INNOVATION</td><td>REGULATED</td><td>OPEN</td></tr>';
|
||
html+='<tr><td>COST MODEL</td><td>THIRD-PARTY PAYER</td><td>DIRECT PAYMENT</td></tr>';
|
||
html+='</table><div class="punch-row"><div class="punch-card"><span class="punch-icon">🧬</span><span class="punch-text">NO GATEKEEPER —<br>YOU CHOOSE YOUR CARE</span></div><div class="punch-card"><span class="punch-icon">🔬</span><span class="punch-text">DIRECT ACCESS —<br>NO INSURANCE APPROVAL NEEDED</span></div><div class="punch-card"><span class="punch-icon">📊</span><span class="punch-text">YOU OWN YOUR DATA —<br>NOT THE SYSTEM</span></div></div>';
|
||
vis.innerHTML=html;
|
||
vis.classList.add('visible');
|
||
showNextBtn('next10e');showNextBtn('sources10e');
|
||
},800);
|
||
h10c.push(t2);
|
||
},undefined,undefined,h10c);
|
||
},1200);
|
||
h10c.push(t1);
|
||
},undefined,undefined,h10c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Scene 11 — Health Summary
|
||
function loadScene11(sceneElem) {
|
||
h10c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=document.getElementById('s11Text');
|
||
const vis=document.getElementById('s11Visual');
|
||
txt.innerHTML='';
|
||
vis.className='s5visual';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('returnFromScene11').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
typeHtmlCalmly(txt,"TRADITIONAL MEDICINE SAVES LIVES — BUT IT ALSO CONTROLS ACCESS.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
txt.innerHTML+="\n\n";
|
||
vis.classList.add('visible');
|
||
let html='<table class="comp-table"><tr><th></th><th>TRADITIONAL</th><th>DECENTRALIZED</th></tr>';
|
||
html+='<tr><td>GATEKEEPERS</td><td>✅ YES — AMERICAN MEDICAL ASSOCIATION, FDA, INSURANCE</td><td>❌ NONE</td></tr>';
|
||
html+='<tr><td>YOUR DATA</td><td>OWNED BY THE SYSTEM</td><td>YOU CONTROL</td></tr>';
|
||
html+='<tr><td>INNOVATION</td><td>APPROVAL-BASED</td><td>PRACTICE-BASED</td></tr>';
|
||
html+='<tr><td>COST</td><td>$4.1T AND RISING</td><td>MARKET-BASED</td></tr>';
|
||
html+='</table><div class="punch-row"><div class="punch-card"><span class="punch-icon">⚖️</span><span class="punch-text">DECENTRALIZED HEALTH<br>DOESN\'T REPLACE DOCTORS</span></div><div class="punch-card"><span class="punch-icon">🔑</span><span class="punch-text">IT REPLACES<br>GATEKEEPERS</span></div><div class="punch-card"><span class="punch-icon">🌐</span><span class="punch-text">THE FUTURE IS<br>OPEN MEDICINE</span></div></div>';
|
||
vis.innerHTML=html;
|
||
typeHtmlCalmly(txt,"THE QUESTION ISN'T WHETHER TO USE TRADITIONAL MEDICINE — IT'S WHO DECIDES WHAT'S AVAILABLE.",()=>{
|
||
txt.innerHTML+="\n\n";
|
||
typeHtmlCalmly(txt,"DECENTRALIZED HEALTH DOESN'T REPLACE DOCTORS. IT REPLACES GATEKEEPERS.",()=>{
|
||
const t6=setTimeout(()=>{
|
||
document.getElementById('returnFromScene11').style.cssText='';
|
||
showNextBtn('returnFromScene11');
|
||
document.getElementById('sources11').style.cssText='';
|
||
showNextBtn('sources11');
|
||
},400);
|
||
h10c.push(t6);
|
||
},8,20,h10c);
|
||
},8,20,h10c);
|
||
},300);
|
||
h10c.push(t1);
|
||
},8,20,h10c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
function buildS6DesktopTable() {
|
||
const rows=[
|
||
['PROPERTY','<span class="nickname">LINUX</span>','macOS','WINDOWS','CHROMEOS'],
|
||
['OPEN SOURCE?','✅ YES','❌ NO','❌ NO','❌ NO'],
|
||
['NO TELEMETRY?','✅ YES','❌ NO','❌ NO','❌ NO'],
|
||
['USER FREEDOM','✅ YES','❌ NO','❌ NO','❌ NO'],
|
||
['FREE?','✅ YES','❌ NO','❌ NO','✅ YES'],
|
||
['RESPECTS PRIVACY?','✅ YES','❌ PARTIAL','❌ NO','❌ NO'],
|
||
];
|
||
let html='<div class="s6section"><div class="s6section-title">DESKTOP OPERATING SYSTEMS</div><table class="comp-table"><tr><th></th><th class="linux-col">LINUX</th><th>macOS</th><th>WINDOWS</th><th>CHROMEOS</th></tr>';
|
||
for(let r=0;r<rows.length;r++){
|
||
const cells=rows[r];
|
||
html+='<tr>';
|
||
for(let c=0;c<cells.length;c++){
|
||
html+='<td'+(c===1?' class="linux-col"':'')+'>'+cells[c]+'</td>';
|
||
}
|
||
html+='</tr>';
|
||
}
|
||
html+='</table></div>';
|
||
return html;
|
||
}
|
||
|
||
function buildS6MobileTable() {
|
||
const rows=[
|
||
['PROPERTY','<span class="nickname">GRAPHENEOS</span>','ANDROID','iOS'],
|
||
['OPEN SOURCE?','✅ YES','✅ YES','❌ NO'],
|
||
['NO GOOGLE TRACKING?','✅ YES','❌ NO','✅ YES'],
|
||
['PRIVACY BY DEFAULT?','✅ YES','❌ NO','❌ PARTIAL'],
|
||
['DE-GOOGLED?','✅ YES','❌ NO','N/A'],
|
||
['SECURITY FOCUSED?','✅ YES','❌ PARTIAL','✅ YES'],
|
||
];
|
||
let html='<div class="s6section"><div class="s6section-title">MOBILE OPERATING SYSTEMS</div><table class="comp-table"><tr><th></th><th class="graphene-col">GRAPHENEOS</th><th>ANDROID</th><th>iOS</th></tr>';
|
||
for(let r=0;r<rows.length;r++){
|
||
const cells=rows[r];
|
||
html+='<tr>';
|
||
for(let c=0;c<cells.length;c++){
|
||
html+='<td'+(c===1?' class="graphene-col"':'')+'>'+cells[c]+'</td>';
|
||
}
|
||
html+='</tr>';
|
||
}
|
||
html+='</table></div>';
|
||
return html;
|
||
}
|
||
|
||
function loadScene6(sceneElem) {
|
||
sceneElem.style.display='flex';
|
||
const hub=document.getElementById('s6TechHub');
|
||
hub.style.opacity='0';
|
||
const title=hub.querySelector('.hub-title');
|
||
const subtitle=document.getElementById('hubSubtitle');
|
||
const rows=hub.querySelectorAll('.hub-row');
|
||
const btns=hub.querySelectorAll('.hub-btn');
|
||
title.classList.remove('visible');
|
||
subtitle.classList.remove('visible');
|
||
rows.forEach(r=>r.classList.remove('visible'));
|
||
btns.forEach(b=>b.classList.remove('visible'));
|
||
sceneElem.style.opacity='0';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
setTimeout(()=>{
|
||
title.classList.add('visible');
|
||
setTimeout(()=>{
|
||
subtitle.classList.add('visible');
|
||
},500);
|
||
rows.forEach((row,i)=>{
|
||
setTimeout(()=>row.classList.add('visible'),(i+1)*400+700);
|
||
});
|
||
setTimeout(()=>{
|
||
btns.forEach((btn,i)=>{
|
||
setTimeout(()=>btn.classList.add('visible'),i*200+100);
|
||
});
|
||
},rows.length*400+900);
|
||
},300);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
hub.style.opacity=o;
|
||
},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) {
|
||
s7c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=document.getElementById('s7Text');
|
||
const canvasDiv=document.getElementById('s7Canvas');
|
||
txt.innerHTML='';
|
||
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;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('s7BtnRow').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
typeCalmly(txt,"YOUR DESKTOP OS DETERMINES WHO CONTROLS YOUR COMPUTER — YOU OR A CORPORATION.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
typeCalmly(txt,"\n\nCLICK A TAB TO SEE HOW EACH OS HANDLES SECURITY AND PRIVACY.",()=>{
|
||
const t2=setTimeout(()=>{
|
||
canvasDiv.classList.add('visible');
|
||
initDeskScene();
|
||
drawDeskScene();
|
||
const status=document.getElementById('deskStatus');
|
||
if(status) status.textContent=deskModeData[deskMode].status;
|
||
},300);
|
||
s7c.push(t2);
|
||
},8,20,s7c);
|
||
},600);
|
||
s7c.push(t1);
|
||
},8,20,s7c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Phone security interactive visualization state
|
||
let phoneAnimId = null;
|
||
let phoneMode = 'grapheneos';
|
||
let phonePackets = [];
|
||
let phoneClicked = false;
|
||
|
||
const phoneModeData = {
|
||
grapheneos: {
|
||
label: 'GRAPHENEOS', color: '#00ff00',
|
||
locks: { camera: true, mic: true, location: true, contacts: true, clipboard: true, network: true, storage: true, sensors: true },
|
||
packetType: 'stay',
|
||
status: 'EVERY PERMISSION REQUIRES EXPLICIT CONSENT — APPS CANNOT ACCESS SENSORS WITHOUT YOUR APPROVAL'
|
||
},
|
||
android: {
|
||
label: 'ANDROID', color: '#ff4444',
|
||
locks: { camera: false, mic: false, location: false, contacts: false, clipboard: false, network: false, storage: false, sensors: false },
|
||
packetType: 'leak',
|
||
status: 'GOOGLE PLAY SERVICES HAS SYSTEM-LEVEL ACCESS TO NEARLY EVERY SENSOR — DATA COLLECTED BY DEFAULT'
|
||
},
|
||
ios: {
|
||
label: 'iOS', color: '#ffff00',
|
||
locks: { camera: false, mic: false, location: true, contacts: false, clipboard: false, network: true, storage: true, sensors: false },
|
||
packetType: 'mixed',
|
||
status: 'APPLE BLOCKS SOME TRACKING BUT STILL COLLECTS DATA THROUGH ITS OWN SERVICES'
|
||
}
|
||
};
|
||
|
||
const phoneTabs = [
|
||
{ id: 'grapheneos', x: 170, w: 130, label: 'GRAPHENEOS' },
|
||
{ id: 'android', x: 335, w: 130, label: 'ANDROID' },
|
||
{ id: 'ios', x: 500, w: 130, label: 'iOS' },
|
||
];
|
||
|
||
const phoneFeatList = [
|
||
{ id: 'camera', label: 'CAMERA', x: 215, y: 100, lx: 365 },
|
||
{ id: 'mic', label: 'MICROPHONE', x: 215, y: 135, lx: 365 },
|
||
{ id: 'clipboard', label: 'CLIPBOARD', x: 215, y: 170, lx: 365 },
|
||
{ id: 'storage', label: 'STORAGE', x: 215, y: 205, lx: 365 },
|
||
{ id: 'location', label: 'LOCATION', x: 440, y: 100, lx: 570 },
|
||
{ id: 'contacts', label: 'CONTACTS', x: 440, y: 135, lx: 570 },
|
||
{ id: 'network', label: 'NETWORK', x: 440, y: 170, lx: 570 },
|
||
{ id: 'sensors', label: 'SENSORS', x: 440, y: 205, lx: 570 },
|
||
];
|
||
|
||
function initPhoneScene() {
|
||
phoneClicked = false;
|
||
phoneMode = 'grapheneos';
|
||
initPhonePackets();
|
||
}
|
||
|
||
function initPhonePackets() {
|
||
const mode = phoneModeData[phoneMode];
|
||
phonePackets = [];
|
||
for (let i = 0; i < 4; i++) {
|
||
const orbit = mode.packetType === 'stay' || (mode.packetType === 'mixed' && i < 2);
|
||
phonePackets.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 drawPhoneScene() {
|
||
const canvas = document.getElementById('phoneCanvas');
|
||
if (!canvas || canvas.offsetParent === null) { phoneAnimId = requestAnimationFrame(drawPhoneScene); return; }
|
||
const ctx = canvas.getContext('2d');
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
const mode = phoneModeData[phoneMode];
|
||
|
||
for (const tab of phoneTabs) {
|
||
const active = tab.id === phoneMode;
|
||
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);
|
||
}
|
||
|
||
ctx.strokeStyle = '#003300';
|
||
ctx.lineWidth = 2;
|
||
ctx.fillStyle = '#000400';
|
||
ctx.beginPath();
|
||
ctx.roundRect(170, 65, 460, 205, 16);
|
||
ctx.fill();
|
||
ctx.stroke();
|
||
|
||
ctx.fillStyle = '#003300';
|
||
ctx.fillRect(370, 65, 60, 4);
|
||
ctx.fillRect(370, 252, 60, 2);
|
||
|
||
for (const feat of phoneFeatList) {
|
||
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 phonePackets) {
|
||
let x, y;
|
||
if (pkt.orbit) {
|
||
const cx = 400, cy = 165;
|
||
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(255, y));
|
||
} else {
|
||
const t = pkt.progress;
|
||
if (t < 0.5) {
|
||
const p = t * 2;
|
||
x = 400 + (pkt.leakX - 400) * p;
|
||
y = 170 + (pkt.leakY - 170) * 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;
|
||
}
|
||
}
|
||
}
|
||
|
||
phoneAnimId = requestAnimationFrame(drawPhoneScene);
|
||
}
|
||
|
||
function handlePhoneCanvasClick(mx, my) {
|
||
const canvas = document.getElementById('phoneCanvas');
|
||
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 phoneTabs) {
|
||
if (cx >= tab.x && cx <= tab.x + tab.w && cy >= 8 && cy <= 30) {
|
||
if (tab.id !== phoneMode) {
|
||
phoneMode = tab.id;
|
||
initPhonePackets();
|
||
const status = document.getElementById('phoneStatus');
|
||
if (status) status.textContent = phoneModeData[phoneMode].status;
|
||
phoneClicked = true;
|
||
const s8Row = document.getElementById('s8BtnRow');
|
||
if (s8Row.style.visibility !== 'visible') {
|
||
s8Row.style.cssText = '';
|
||
s8Row.style.visibility = 'visible';
|
||
let ro = 0;
|
||
const rfi = setInterval(() => {
|
||
ro += 0.05; if (ro >= 1) { ro = 1; clearInterval(rfi); s8Row.style.pointerEvents = 'auto'; }
|
||
s8Row.style.opacity = ro;
|
||
}, 30);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
function loadScene8(sceneElem) {
|
||
s8c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=document.getElementById('s8Text');
|
||
const canvasDiv=document.getElementById('s8Canvas');
|
||
txt.innerHTML='';
|
||
canvasDiv.classList.remove('visible');
|
||
if (phoneAnimId) { cancelAnimationFrame(phoneAnimId); phoneAnimId = null; }
|
||
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
|
||
const s8Row = document.getElementById('s8BtnRow');
|
||
s8Row.style.visibility = 'hidden';
|
||
s8Row.style.opacity = '0';
|
||
s8Row.style.pointerEvents = 'none';
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('s8BtnRow').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
typeCalmly(txt,"YOUR PHONE IS LITERALLY A TRACKING DEVICE IN YOUR POCKET — UNLESS YOU CHOOSE OTHERWISE.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
typeCalmly(txt,"\n\nGRAPHENEOS LOCKS DOWN EVERY SENSOR AND PERMISSION — CLICK A TAB TO SEE THE DIFFERENCE.",()=>{
|
||
const t2=setTimeout(()=>{
|
||
canvasDiv.classList.add('visible');
|
||
initPhoneScene();
|
||
drawPhoneScene();
|
||
const status=document.getElementById('phoneStatus');
|
||
if(status) status.textContent=phoneModeData[phoneMode].status;
|
||
},300);
|
||
s8c.push(t2);
|
||
},8,20,s8c);
|
||
},600);
|
||
s8c.push(t1);
|
||
},8,20,s8c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
// Mesh network interactive visualization state
|
||
let meshAnimId = null;
|
||
let meshClicked = false;
|
||
let meshState = null;
|
||
|
||
function initMesh() {
|
||
meshClicked = false;
|
||
meshState = {
|
||
nodes: [
|
||
{ id: 0, x: 130, y: 45, label: 'A', online: true },
|
||
{ id: 1, x: 480, y: 35, label: 'B', online: true },
|
||
{ id: 2, x: 700, y: 75, label: 'C', online: true },
|
||
{ id: 3, x: 70, y: 130, label: 'D', online: true },
|
||
{ id: 4, x: 390, y: 105, label: 'E', online: true },
|
||
{ id: 5, x: 660, y: 165, label: 'F', online: true },
|
||
{ id: 6, x: 230, y: 195, label: 'G', online: true },
|
||
{ id: 7, x: 540, y: 215, label: 'H', online: true },
|
||
{ id: 8, x: 110, y: 265, label: 'I', online: true },
|
||
{ id: 9, x: 350, y: 285, label: 'J', online: true },
|
||
{ id: 10, x: 670, y: 245, label: 'K', online: true },
|
||
{ id: 11, x: 590, y: 310, label: 'L', online: true },
|
||
],
|
||
packets: [],
|
||
};
|
||
computeConnections();
|
||
for (let i = 0; i < 5; i++) spawnPacket();
|
||
}
|
||
|
||
function computeConnections() {
|
||
const online = meshState.nodes.filter(n => n.online);
|
||
for (const node of meshState.nodes) {
|
||
if (!node.online) { node.connections = []; continue; }
|
||
const distances = online
|
||
.filter(n => n.id !== node.id && n.online)
|
||
.map(n => ({ node: n, dist: Math.hypot(n.x - node.x, n.y - node.y) }))
|
||
.sort((a, b) => a.dist - b.dist);
|
||
node.connections = distances.slice(0, 4).map(d => d.node.id);
|
||
}
|
||
ensureConnectivity();
|
||
}
|
||
|
||
function ensureConnectivity() {
|
||
const online = meshState.nodes.filter(n => n.online);
|
||
if (online.length < 2) return;
|
||
const adj = {};
|
||
for (const node of online) {
|
||
adj[node.id] = node.connections.filter(cid => {
|
||
const cn = meshState.nodes.find(n => n.id === cid);
|
||
return cn && cn.online;
|
||
});
|
||
}
|
||
const visited = new Set();
|
||
const queue = [online[0].id];
|
||
visited.add(online[0].id);
|
||
while (queue.length) {
|
||
const cur = queue.shift();
|
||
for (const nb of (adj[cur] || [])) {
|
||
if (!visited.has(nb)) {
|
||
visited.add(nb);
|
||
queue.push(nb);
|
||
}
|
||
}
|
||
}
|
||
const unreachable = online.filter(n => !visited.has(n.id));
|
||
for (const orphan of unreachable) {
|
||
let best = null;
|
||
let bestDist = Infinity;
|
||
for (const node of meshState.nodes) {
|
||
if (!node.online || !visited.has(node.id)) continue;
|
||
const d = Math.hypot(orphan.x - node.x, orphan.y - node.y);
|
||
if (d < bestDist) {
|
||
bestDist = d;
|
||
best = node;
|
||
}
|
||
}
|
||
if (best) {
|
||
orphan.connections.push(best.id);
|
||
best.connections.push(orphan.id);
|
||
visited.add(orphan.id);
|
||
}
|
||
}
|
||
}
|
||
|
||
function spawnPacket() {
|
||
const online = meshState.nodes.filter(n => n.online);
|
||
if (online.length < 2) return;
|
||
const from = online[Math.floor(Math.random() * online.length)];
|
||
if (!from.connections || from.connections.length === 0) return;
|
||
const toId = from.connections[Math.floor(Math.random() * from.connections.length)];
|
||
const to = meshState.nodes.find(n => n.id === toId);
|
||
if (!to || !to.online) return;
|
||
meshState.packets.push({ fromId: from.id, toId: to.id, progress: Math.random() });
|
||
}
|
||
|
||
function drawMesh() {
|
||
const canvas = document.getElementById('meshCanvas');
|
||
if (!canvas || canvas.offsetParent === null) { meshAnimId = requestAnimationFrame(drawMesh); return; }
|
||
const ctx = canvas.getContext('2d');
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
|
||
for (const node of meshState.nodes) {
|
||
if (!node.online) continue;
|
||
for (const connId of node.connections) {
|
||
const conn = meshState.nodes.find(n => n.id === connId);
|
||
if (!conn || !conn.online) continue;
|
||
ctx.strokeStyle = '#003300';
|
||
ctx.lineWidth = 1;
|
||
ctx.beginPath();
|
||
ctx.moveTo(node.x, node.y);
|
||
ctx.lineTo(conn.x, conn.y);
|
||
ctx.stroke();
|
||
}
|
||
}
|
||
|
||
for (const pkt of meshState.packets) {
|
||
const from = meshState.nodes.find(n => n.id === pkt.fromId);
|
||
const to = meshState.nodes.find(n => n.id === pkt.toId);
|
||
if (!from || !to || !from.online || !to.online) continue;
|
||
const x = from.x + (to.x - from.x) * pkt.progress;
|
||
const y = from.y + (to.y - from.y) * pkt.progress;
|
||
ctx.shadowColor = '#ffff00';
|
||
ctx.shadowBlur = 10;
|
||
ctx.fillStyle = '#ffff00';
|
||
ctx.beginPath();
|
||
ctx.arc(x, y, 5, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
ctx.shadowBlur = 0;
|
||
}
|
||
|
||
for (const node of meshState.nodes) {
|
||
const color = node.online ? '#00ff00' : '#ff4444';
|
||
if (node.online) {
|
||
ctx.shadowColor = '#00ff00';
|
||
ctx.shadowBlur = 12;
|
||
}
|
||
ctx.fillStyle = color;
|
||
ctx.beginPath();
|
||
ctx.arc(node.x, node.y, 12, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
ctx.shadowBlur = 0;
|
||
ctx.strokeStyle = color;
|
||
ctx.lineWidth = 2;
|
||
if (!node.online) ctx.setLineDash([3, 3]);
|
||
ctx.beginPath();
|
||
ctx.arc(node.x, node.y, 12, 0, Math.PI * 2);
|
||
ctx.stroke();
|
||
ctx.setLineDash([]);
|
||
ctx.fillStyle = color;
|
||
ctx.font = 'bold 11px Courier New, monospace';
|
||
ctx.textAlign = 'center';
|
||
ctx.textBaseline = 'middle';
|
||
ctx.fillText(node.label, node.x, node.y + 24);
|
||
}
|
||
|
||
for (const pkt of meshState.packets) {
|
||
pkt.progress += 0.01;
|
||
if (pkt.progress >= 1) {
|
||
pkt.progress = 0;
|
||
pkt.fromId = pkt.toId;
|
||
const from = meshState.nodes.find(n => n.id === pkt.fromId);
|
||
if (!from || !from.online) {
|
||
const online = meshState.nodes.filter(n => n.online);
|
||
if (online.length > 0) pkt.fromId = online[Math.floor(Math.random() * online.length)].id;
|
||
}
|
||
const from2 = meshState.nodes.find(n => n.id === pkt.fromId);
|
||
if (from2 && from2.online && from2.connections) {
|
||
const valid = from2.connections.filter(cid => {
|
||
const cn = meshState.nodes.find(n => n.id === cid);
|
||
return cn && cn.online;
|
||
});
|
||
pkt.toId = valid.length > 0 ? valid[Math.floor(Math.random() * valid.length)] : pkt.fromId;
|
||
}
|
||
}
|
||
}
|
||
|
||
meshState.packets = meshState.packets.filter(p => {
|
||
const from = meshState.nodes.find(n => n.id === p.fromId);
|
||
const to = meshState.nodes.find(n => n.id === p.toId);
|
||
return from && to && from.online && to.online && p.fromId !== p.toId;
|
||
});
|
||
while (meshState.packets.length < 4) spawnPacket();
|
||
|
||
meshAnimId = requestAnimationFrame(drawMesh);
|
||
}
|
||
|
||
function toggleMeshNode(mx, my) {
|
||
const canvas = document.getElementById('meshCanvas');
|
||
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 node of meshState.nodes) {
|
||
if (Math.hypot(cx - node.x, cy - node.y) < 20) {
|
||
node.online = !node.online;
|
||
meshState.packets = meshState.packets.filter(p => p.fromId !== node.id && p.toId !== node.id);
|
||
computeConnections();
|
||
const status = document.getElementById('meshStatus');
|
||
if (status) {
|
||
status.textContent = node.online
|
||
? 'NODE ' + node.label + ' RESTORED — MESH PATH FOUND'
|
||
: 'NODE ' + node.label + ' OFFLINE — MESH REROUTED';
|
||
}
|
||
meshClicked = true;
|
||
if (document.getElementById('returnFromScene9').style.visibility !== 'visible') {
|
||
document.getElementById('returnFromScene9').style.cssText = '';
|
||
showNextBtn('returnFromScene9');
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
function loadScene9(sceneElem) {
|
||
s9c=[];
|
||
sceneElem.style.display='flex';
|
||
const txt=document.getElementById('s9Text');
|
||
const canvasDiv=document.getElementById('s9Canvas');
|
||
txt.innerHTML='';
|
||
canvasDiv.classList.remove('visible');
|
||
if (meshAnimId) { cancelAnimationFrame(meshAnimId); meshAnimId = null; }
|
||
let o=0;
|
||
const fi=setInterval(()=>{
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('returnFromScene9').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
||
typeCalmly(txt,"THE INTERNET WAS DESIGNED TO BE DECENTRALIZED — BUT ISPS HAVE TURNED IT INTO A UTILITY CONTROLLED BY GATEKEEPERS.",()=>{
|
||
const t1=setTimeout(()=>{
|
||
typeCalmly(txt,"\n\nMESH NETWORKS AND P2P PROTOCOLS LET COMMUNITIES BUILD THEIR OWN INTERNET — NO ISP REQUIRED.",()=>{
|
||
const t2=setTimeout(()=>{
|
||
canvasDiv.classList.add('visible');
|
||
initMesh();
|
||
drawMesh();
|
||
const status=document.getElementById('meshStatus');
|
||
if(status) status.textContent='CLICK ANY NODE TO SEE HOW MESH NETWORKS REROUTE WHEN A NODE GOES OFFLINE';
|
||
},300);
|
||
s9c.push(t2);
|
||
},8,20,s9c);
|
||
},600);
|
||
s9c.push(t1);
|
||
},8,20,s9c);
|
||
}
|
||
sceneElem.style.opacity=o;
|
||
},30);
|
||
}
|
||
|
||
let s4c = [];
|
||
let s5c = [];
|
||
let h10c = [];
|
||
let s2c = [];
|
||
let s7c = [];
|
||
let s8c = [];
|
||
let s9c = [];
|
||
let s8bc = [];
|
||
let s7bc = [];
|
||
|
||
// Scene 8b — Data Exfiltration Simulator
|
||
let exfilAnimId = null;
|
||
let exfilMode = 'grapheneos';
|
||
let exfilPackets = [];
|
||
let exfilCounter = 0;
|
||
let exfilCounterTarget = 0;
|
||
|
||
const exfilModeData = {
|
||
grapheneos: { label: 'GRAPHENEOS', counterMax: 0, color: '#00ff00', status: 'YOUR DATA STAYS ON YOUR DEVICE. NO TRACKING. NO PROFILING.' },
|
||
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: 150, color: '#ffff00', status: 'APPLE COLLECTS DATA THROUGH ITS SERVICES. SOME THIRD-PARTY TRACKING IS BLOCKED.' },
|
||
};
|
||
|
||
const exfilTabs = [
|
||
{ id: 'grapheneos', x: 170, w: 130, label: 'GRAPHENEOS' },
|
||
{ id: 'android', x: 335, w: 130, label: 'ANDROID' },
|
||
{ id: 'ios', x: 500, w: 130, label: 'iOS' },
|
||
];
|
||
|
||
const exfilServers = {
|
||
grapheneos: [],
|
||
android: [
|
||
{ id: 'google', label: 'GOOGLE', x: 540, y: 55, w: 100, h: 34, color: '#4285f4' },
|
||
{ id: 'broker', label: 'DATA BROKER', x: 645, y: 115, w: 115, h: 34, color: '#ff6644' },
|
||
{ id: 'ads', label: 'AD NETWORKS', x: 555, y: 195, w: 115, h: 34, color: '#ff44ff' },
|
||
{ id: 'hacker', label: 'HACKER', x: 635, y: 285, w: 100, h: 34, color: '#ff0000' },
|
||
],
|
||
ios: [
|
||
{ 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' },
|
||
],
|
||
};
|
||
|
||
const exfilDataTypes = [
|
||
{ id: 'location', label: 'LOC', color: '#ff6644' },
|
||
{ id: 'contacts', label: 'CONTACTS', color: '#44aaff' },
|
||
{ id: 'camera', label: 'CAMERA', color: '#ff44ff' },
|
||
{ id: 'mic', label: 'MIC', color: '#ffff44' },
|
||
{ id: 'browsing', label: 'BROWSING', color: '#44ffaa' },
|
||
{ id: 'sms', label: 'SMS', color: '#ff8844' },
|
||
];
|
||
|
||
function initExfilScene() {
|
||
exfilMode = 'grapheneos';
|
||
exfilPackets = [];
|
||
exfilCounter = 0;
|
||
exfilCounterTarget = 0;
|
||
const legend = document.getElementById('exfilLegend');
|
||
if (legend) {
|
||
legend.innerHTML = '';
|
||
for (const dt of exfilDataTypes) {
|
||
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 spawnExfilPacket() {
|
||
const servers = exfilServers[exfilMode];
|
||
if (servers.length === 0) return;
|
||
const server = servers[Math.floor(Math.random() * servers.length)];
|
||
const dataType = exfilDataTypes[Math.floor(Math.random() * exfilDataTypes.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;
|
||
exfilPackets.push({
|
||
fromX, fromY, toX, toY,
|
||
dataType,
|
||
progress: 0,
|
||
speed: 0.008 + Math.random() * 0.006,
|
||
});
|
||
}
|
||
|
||
function drawExfilScene() {
|
||
const canvas = document.getElementById('exfilCanvas');
|
||
if (!canvas || canvas.offsetParent === null) { exfilAnimId = requestAnimationFrame(drawExfilScene); return; }
|
||
const ctx = canvas.getContext('2d');
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
const mode = exfilModeData[exfilMode];
|
||
const servers = exfilServers[exfilMode];
|
||
|
||
// Tabs
|
||
for (const tab of exfilTabs) {
|
||
const active = tab.id === exfilMode;
|
||
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);
|
||
}
|
||
|
||
// Phone silhouette
|
||
const px = 70, py = 60, pw = 140, ph = 250;
|
||
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;
|
||
|
||
// Phone screen
|
||
ctx.fillStyle = '#001100';
|
||
ctx.beginPath();
|
||
ctx.roundRect(px + 8, py + 35, pw - 16, ph - 55, 6);
|
||
ctx.fill();
|
||
|
||
// Camera dot
|
||
ctx.fillStyle = '#003300';
|
||
ctx.beginPath();
|
||
ctx.arc(px + pw / 2, py + 16, 4, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// Phone label
|
||
ctx.fillStyle = mode.color;
|
||
ctx.font = 'bold 12px Courier New, monospace';
|
||
ctx.textAlign = 'center';
|
||
ctx.textBaseline = 'middle';
|
||
ctx.fillText(exfilMode === 'grapheneos' ? '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);
|
||
}
|
||
|
||
// Spawn packets
|
||
if (servers.length > 0 && Math.random() < 0.06) spawnExfilPacket();
|
||
|
||
// Draw and update packets
|
||
for (let i = exfilPackets.length - 1; i >= 0; i--) {
|
||
const pkt = exfilPackets[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) {
|
||
exfilPackets.splice(i, 1);
|
||
if (exfilCounterTarget < mode.counterMax) {
|
||
exfilCounterTarget = Math.min(mode.counterMax, exfilCounterTarget + 18);
|
||
}
|
||
}
|
||
}
|
||
|
||
while (exfilPackets.length > 30) exfilPackets.shift();
|
||
|
||
// Smooth counter
|
||
if (exfilCounter < exfilCounterTarget) {
|
||
exfilCounter = Math.min(exfilCounterTarget, exfilCounter + 5);
|
||
} else if (exfilCounter > exfilCounterTarget) {
|
||
exfilCounter = Math.max(exfilCounterTarget, exfilCounter - 5);
|
||
}
|
||
const ce = document.getElementById('exfilCounter');
|
||
if (ce) {
|
||
ce.textContent = 'DATA VALUE EXPOSED: $' + exfilCounter.toFixed(0) + '/yr';
|
||
ce.style.color = exfilCounter > 0 ? '#ff4444' : '#00ff00';
|
||
}
|
||
|
||
const st = document.getElementById('exfilStatus');
|
||
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);
|
||
}
|
||
|
||
function handleExfilCanvasClick(mx, my) {
|
||
const canvas = document.getElementById('exfilCanvas');
|
||
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 exfilTabs) {
|
||
if (cx >= tab.x && cx <= tab.x + tab.w && cy >= 8 && cy <= 30) {
|
||
if (tab.id !== exfilMode) {
|
||
exfilMode = tab.id;
|
||
exfilPackets = [];
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
|
||
function loadScene8b(sceneElem) {
|
||
s8bc = [];
|
||
sceneElem.style.display = 'flex';
|
||
const txt = document.getElementById('s8bText');
|
||
const canvasDiv = document.getElementById('s8bCanvas');
|
||
txt.innerHTML = '';
|
||
canvasDiv.classList.remove('visible');
|
||
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
|
||
let o = 0;
|
||
const fi = setInterval(() => {
|
||
if (sceneElem.style.display !== 'flex' || document.getElementById('returnFromScene8b').style.visibility === 'visible') { clearInterval(fi); return; }
|
||
o += 0.05; if (o >= 1) { o = 1; clearInterval(fi);
|
||
typeCalmly(txt, "EACH TIME YOUR PHONE SENDS DATA TO THIRD-PARTY SERVERS, IT CREATES A DIGITAL PROFILE OF YOU — SOLD TO THE HIGHEST BIDDER.", () => {
|
||
const t1 = setTimeout(() => {
|
||
typeCalmly(txt, "\n\nCLICK THE TABS TO SEE WHERE YOUR DATA ACTUALLY GOES.", () => {
|
||
const t2 = setTimeout(() => {
|
||
canvasDiv.classList.add('visible');
|
||
initExfilScene();
|
||
drawExfilScene();
|
||
}, 300);
|
||
s8bc.push(t2);
|
||
}, 8, 20, s8bc);
|
||
}, 600);
|
||
s8bc.push(t1);
|
||
}, 8, 20, s8bc);
|
||
}
|
||
sceneElem.style.opacity = o;
|
||
}, 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
|
||
window.addEventListener('load', () => {
|
||
if (sessionStorage.getItem('returnToScene') === 'scene3') {
|
||
sessionStorage.removeItem('returnToScene');
|
||
document.getElementById('matrixCanvas').style.display = 'none';
|
||
document.getElementById('textContainer').style.display = 'none';
|
||
document.getElementById('followBtn').style.display = 'none';
|
||
loadScene3(document.getElementById('scene3'));
|
||
} else {
|
||
setTimeout(crtFlicker, 1500);
|
||
}
|
||
});
|
||
|
||
// Button click handlers
|
||
document.getElementById('followBtn').addEventListener('click', () => {
|
||
document.getElementById('followBtn').disabled = true;
|
||
transitionToScene2();
|
||
});
|
||
document.getElementById('whatIsLabBtn').addEventListener('click', () => {
|
||
transitionToScene('scene2', loadScene3, 'scene3');
|
||
});
|
||
document.getElementById('yourMoneyBtn').addEventListener('click', () => {
|
||
transitionToScene('scene3', loadScene4a, 'scene4a');
|
||
});
|
||
document.getElementById('yourTechBtn').addEventListener('click', () => {
|
||
transitionToScene('scene3', loadScene6, 'scene6');
|
||
});
|
||
document.getElementById('yourFoodBtn').addEventListener('click', () => {
|
||
document.getElementById('foodOverlay').classList.add('visible');
|
||
});
|
||
document.getElementById('foodVimeo').addEventListener('click', () => {
|
||
sessionStorage.setItem('returnToScene', 'scene3');
|
||
window.location.href = 'https://vimeo.com/801031681/eb502b3911';
|
||
});
|
||
document.getElementById('foodKitchen').addEventListener('click', () => {
|
||
sessionStorage.setItem('returnToScene', 'scene3');
|
||
window.location.href = 'https://484.kitchen';
|
||
});
|
||
document.getElementById('foodClose').addEventListener('click', () => {
|
||
document.getElementById('foodOverlay').classList.remove('visible');
|
||
});
|
||
document.getElementById('yourHealthBtn').addEventListener('click', () => {
|
||
transitionToScene('scene3', loadScene10a, 'scene10a');
|
||
});
|
||
document.getElementById('next4a').addEventListener('click', () => {
|
||
document.getElementById('scene4a').style.display = 'none';
|
||
loadScene4b(document.getElementById('scene4b'));
|
||
});
|
||
document.getElementById('next4b').addEventListener('click', () => {
|
||
document.getElementById('scene4b').style.display = 'none';
|
||
loadScene4c(document.getElementById('scene4c'));
|
||
});
|
||
document.getElementById('next4c').addEventListener('click', () => {
|
||
document.getElementById('scene4c').style.display = 'none';
|
||
loadScene4d(document.getElementById('scene4d'));
|
||
});
|
||
document.getElementById('next4d').addEventListener('click', () => {
|
||
document.getElementById('scene4d').style.display = 'none';
|
||
loadScene4e(document.getElementById('scene4e'));
|
||
});
|
||
document.getElementById('next4e').addEventListener('click', () => {
|
||
document.getElementById('scene4e').style.display = 'none';
|
||
loadScene5(document.getElementById('scene5'));
|
||
});
|
||
document.getElementById('returnFromScene5').addEventListener('click', () => {
|
||
document.getElementById('scene5').style.display = 'none';
|
||
const s3 = document.getElementById('scene3');
|
||
scene3TypewriterTimeouts.forEach(t => clearTimeout(t));
|
||
scene3TypewriterTimeouts = [];
|
||
s3.style.display = 'flex';
|
||
s3.style.opacity = '1';
|
||
document.getElementById('scene3Title').classList.add('visible');
|
||
document.getElementById('scene3Text').innerHTML = "IS AN INCUBATOR THAT HAS MANY DECENTRALIZED STARTUPS UNDERNEATH IT<br><br><br><br><br><br><br><br><div style=\"text-align:center\">WE BELIEVE EVERYTHING SHOULD BE DECENTRALIZED</div>";
|
||
const row = document.getElementById('scene3ChoiceRow');
|
||
row.style.display = 'flex';
|
||
const btns = row.querySelectorAll('.scene3ChoiceBtn');
|
||
btns.forEach(btn => {
|
||
btn.style.opacity = '0';
|
||
btn.style.pointerEvents = 'none';
|
||
});
|
||
setTimeout(() => {
|
||
btns.forEach(btn => {
|
||
btn.style.opacity = '1';
|
||
btn.style.pointerEvents = 'auto';
|
||
});
|
||
}, 500);
|
||
});
|
||
|
||
document.getElementById('next10a').addEventListener('click', () => {
|
||
document.getElementById('scene10a').style.display = 'none';
|
||
loadScene10b(document.getElementById('scene10b'));
|
||
});
|
||
document.getElementById('next10b').addEventListener('click', () => {
|
||
document.getElementById('scene10b').style.display = 'none';
|
||
loadScene10c(document.getElementById('scene10c'));
|
||
});
|
||
document.getElementById('next10c').addEventListener('click', () => {
|
||
document.getElementById('scene10c').style.display = 'none';
|
||
loadScene10d(document.getElementById('scene10d'));
|
||
});
|
||
document.getElementById('next10d').addEventListener('click', () => {
|
||
document.getElementById('scene10d').style.display = 'none';
|
||
loadScene10e(document.getElementById('scene10e'));
|
||
});
|
||
document.getElementById('next10e').addEventListener('click', () => {
|
||
document.getElementById('scene10e').style.display = 'none';
|
||
loadScene11(document.getElementById('scene11'));
|
||
});
|
||
document.getElementById('returnFromScene11').addEventListener('click', () => {
|
||
document.getElementById('scene11').style.display = 'none';
|
||
const s3 = document.getElementById('scene3');
|
||
scene3TypewriterTimeouts.forEach(t => clearTimeout(t));
|
||
scene3TypewriterTimeouts = [];
|
||
s3.style.display = 'flex';
|
||
s3.style.opacity = '1';
|
||
document.getElementById('scene3Title').classList.add('visible');
|
||
document.getElementById('scene3Text').innerHTML = "IS AN INCUBATOR THAT HAS MANY DECENTRALIZED STARTUPS UNDERNEATH IT<br><br><br><br><br><br><br><br><div style=\"text-align:center\">WE BELIEVE EVERYTHING SHOULD BE DECENTRALIZED</div>";
|
||
const row = document.getElementById('scene3ChoiceRow');
|
||
row.style.display = 'flex';
|
||
const btns = row.querySelectorAll('.scene3ChoiceBtn');
|
||
btns.forEach(btn => {
|
||
btn.style.opacity = '0';
|
||
btn.style.pointerEvents = 'none';
|
||
});
|
||
setTimeout(() => {
|
||
btns.forEach(btn => {
|
||
btn.style.opacity = '1';
|
||
btn.style.pointerEvents = 'auto';
|
||
});
|
||
}, 500);
|
||
});
|
||
|
||
['4a','4b','4c','4d','4e','5','10a','10b','10c','10d','10e','11'].forEach(function(id){
|
||
document.getElementById('sources'+id).addEventListener('click',function(){
|
||
window.refsCaller='scene'+id;
|
||
document.getElementById('scene'+id).style.display='none';
|
||
document.getElementById('sceneRefs').classList.add('visible');
|
||
});
|
||
});
|
||
|
||
document.getElementById('goDesktopTech').addEventListener('click', () => {
|
||
transitionToScene('scene6', loadScene7, 'scene7');
|
||
});
|
||
document.getElementById('goMobileTech').addEventListener('click', () => {
|
||
transitionToScene('scene6', loadScene8, 'scene8');
|
||
});
|
||
document.getElementById('goInternetTech').addEventListener('click', () => {
|
||
transitionToScene('scene6', loadScene9, 'scene9');
|
||
});
|
||
document.getElementById('returnFromTechHub').addEventListener('click', () => {
|
||
document.getElementById('scene6').style.display = 'none';
|
||
const s3 = document.getElementById('scene3');
|
||
scene3TypewriterTimeouts.forEach(t => clearTimeout(t));
|
||
scene3TypewriterTimeouts = [];
|
||
s3.style.display = 'flex';
|
||
s3.style.opacity = '1';
|
||
document.getElementById('scene3Title').classList.add('visible');
|
||
document.getElementById('scene3Text').innerHTML = "IS AN INCUBATOR THAT HAS MANY DECENTRALIZED STARTUPS UNDERNEATH IT<br><br><br><br><br><br><br><br><div style=\"text-align:center\">WE BELIEVE EVERYTHING SHOULD BE DECENTRALIZED</div>";
|
||
const row = document.getElementById('scene3ChoiceRow');
|
||
row.style.display = 'flex';
|
||
const btns = row.querySelectorAll('.scene3ChoiceBtn');
|
||
btns.forEach(btn => {
|
||
btn.style.opacity = '0';
|
||
btn.style.pointerEvents = 'none';
|
||
});
|
||
setTimeout(() => {
|
||
btns.forEach(btn => {
|
||
btn.style.opacity = '1';
|
||
btn.style.pointerEvents = 'auto';
|
||
});
|
||
}, 500);
|
||
});
|
||
|
||
function showTechHub() {
|
||
if (meshAnimId) { cancelAnimationFrame(meshAnimId); meshAnimId = null; }
|
||
if (phoneAnimId) { cancelAnimationFrame(phoneAnimId); phoneAnimId = null; }
|
||
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
|
||
if (deskAnimId) { cancelAnimationFrame(deskAnimId); deskAnimId = null; }
|
||
if (exfilDeskAnimId) { cancelAnimationFrame(exfilDeskAnimId); exfilDeskAnimId = null; }
|
||
const s6 = document.getElementById('scene6');
|
||
s6.style.display = 'flex';
|
||
s6.style.opacity = '1';
|
||
const hub = document.getElementById('s6TechHub');
|
||
hub.style.opacity = '1';
|
||
hub.querySelector('.hub-title').classList.add('visible');
|
||
document.getElementById('hubSubtitle').classList.add('visible');
|
||
hub.querySelectorAll('.hub-row').forEach(r => r.classList.add('visible'));
|
||
hub.querySelectorAll('.hub-btn').forEach(b => b.classList.add('visible'));
|
||
}
|
||
|
||
document.getElementById('returnFromScene7').addEventListener('click', () => {
|
||
document.getElementById('scene7').style.display = 'none';
|
||
showTechHub();
|
||
});
|
||
|
||
document.getElementById('returnFromScene8').addEventListener('click', () => {
|
||
document.getElementById('scene8').style.display = 'none';
|
||
showTechHub();
|
||
});
|
||
|
||
document.getElementById('returnFromScene9').addEventListener('click', () => {
|
||
document.getElementById('scene9').style.display = 'none';
|
||
showTechHub();
|
||
});
|
||
|
||
document.getElementById('meshCanvas').addEventListener('click', (e) => {
|
||
if (meshState) toggleMeshNode(e.clientX, e.clientY);
|
||
});
|
||
|
||
document.getElementById('phoneCanvas').addEventListener('click', (e) => {
|
||
handlePhoneCanvasClick(e.clientX, e.clientY);
|
||
});
|
||
|
||
document.getElementById('deskCanvas').addEventListener('click', (e) => {
|
||
handleDeskCanvasClick(e.clientX, e.clientY);
|
||
});
|
||
|
||
document.getElementById('exfilCanvas').addEventListener('click', (e) => {
|
||
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', () => {
|
||
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
|
||
if (phoneAnimId) { cancelAnimationFrame(phoneAnimId); phoneAnimId = null; }
|
||
document.getElementById('scene8').style.display = 'none';
|
||
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', () => {
|
||
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
|
||
document.getElementById('scene8b').style.display = 'none';
|
||
showTechHub();
|
||
});
|
||
|
||
// Keyboard shortcuts for testing
|
||
document.addEventListener('keydown', (e) => {
|
||
if (e.key === 'Escape') {
|
||
// SceneRefs: return to caller
|
||
const refsDiv = document.getElementById('sceneRefs');
|
||
if (refsDiv.classList.contains('visible')) {
|
||
refsDiv.classList.remove('visible');
|
||
var c=refsCaller;if(c==='scene7b'||c==='scene8b'||c==='scene4a'||c==='scene4b'||c==='scene4c'||c==='scene4d'||c==='scene4e'||c==='scene5')document.getElementById(c).style.display='flex';
|
||
refsCaller = null;
|
||
return;
|
||
}
|
||
|
||
// 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') {
|
||
canvas.style.opacity = '0.15';
|
||
skipScene1();
|
||
}
|
||
|
||
// Scene 2 skip (calm typing)
|
||
const scene2 = document.getElementById('scene2');
|
||
const s2Cursor = document.getElementById('scene2Cursor');
|
||
const s2Cursor2 = document.getElementById('scene2Cursor2');
|
||
const s2Message = document.getElementById('scene2Message');
|
||
const s2Message2 = document.getElementById('scene2Message2');
|
||
const s2Line2 = document.getElementById('scene2Line2');
|
||
const s2Btn = document.getElementById('whatIsLabBtn');
|
||
if (scene2.style.display === 'flex' && s2Btn.style.visibility !== 'visible') {
|
||
s2c.forEach(t => clearTimeout(t));
|
||
s2c = [];
|
||
s2Cursor.style.display = 'none';
|
||
s2Cursor2.style.display = 'none';
|
||
s2Message.textContent = '...AND THAT AWARENESS HAS LED YOU HERE...';
|
||
s2Line2.style.display = 'flex';
|
||
s2Message2.textContent = 'TO LAB 484';
|
||
s2Btn.style.visibility = 'visible';
|
||
s2Btn.style.opacity = '1';
|
||
s2Btn.style.pointerEvents = 'auto';
|
||
}
|
||
|
||
// Scene 3 skip (incubator text + choice buttons)
|
||
const scene3 = document.getElementById('scene3');
|
||
const s3ChoiceRow = document.getElementById('scene3ChoiceRow');
|
||
if (scene3.style.display === 'flex' && s3ChoiceRow.style.display !== 'flex') {
|
||
scene3TypewriterTimeouts.forEach(t => clearTimeout(t));
|
||
scene3TypewriterTimeouts = [];
|
||
document.getElementById('scene3Text').innerHTML =
|
||
"IS AN INCUBATOR THAT HAS MANY DECENTRALIZED STARTUPS UNDERNEATH IT<br><br><br><br><br><br><br><br><div style=\"text-align:center\">WE BELIEVE EVERYTHING SHOULD BE DECENTRALIZED</div>";
|
||
s3ChoiceRow.style.display = 'flex';
|
||
const btns3 = s3ChoiceRow.querySelectorAll('.scene3ChoiceBtn');
|
||
btns3.forEach(btn => {
|
||
btn.style.opacity = '0';
|
||
btn.style.pointerEvents = 'none';
|
||
});
|
||
setTimeout(() => {
|
||
btns3.forEach(btn => {
|
||
btn.style.opacity = '1';
|
||
btn.style.pointerEvents = 'auto';
|
||
});
|
||
}, 500);
|
||
}
|
||
|
||
// Scene 4 skip (sub-scenes 4a-4e)
|
||
const s4ids = ['scene4a','scene4b','scene4c','scene4d','scene4e'];
|
||
for (let si=0; si<s4ids.length; si++) {
|
||
const s4 = document.getElementById(s4ids[si]);
|
||
if (s4.style.display === 'flex') {
|
||
s4c.forEach(t => clearTimeout(t)); s4c = [];
|
||
const txt = s4.querySelector('.scene4text');
|
||
const tl = s4.querySelector('.s4tl');
|
||
buildTimeline(tl, si);
|
||
if (si===0) {
|
||
txt.innerHTML = "IMAGINE THE GOVERNMENT SHOWED UP AT YOUR DOOR AND DEMANDED YOUR SAVINGS.\n\nTHAT'S NOT HYPOTHETICAL — IT HAPPENED IN 1933.\n\nIN 1900, THE GOLD STANDARD ACT WAS PASSED. EVERY DOLLAR WAS BACKED BY GOLD — REAL, TANGIBLE, TRUSTWORTHY. <a href=\"https://www.gold.org/sites/default/files/documents/1900mar14.pdf\" target=\"_blank\" style=\"text-decoration:underline;font-weight:bold;color:#00ff00\">THE GOLD STANDARD ACT OF 1900</a>";
|
||
document.getElementById('next4a').style.cssText = '';
|
||
showNextBtn('next4a');
|
||
document.getElementById('sources4a').style.cssText = '';
|
||
showNextBtn('sources4a');
|
||
} else if (si===1) {
|
||
txt.innerHTML = "ON APRIL 5, 1933, <a href=\"https://www.usmoneyreserve.com/resources/videos/transcripts/executive-order-6102-did-you-know/\" target=\"_blank\" style=\"text-decoration:underline;font-weight:bold;color:#00ff00\">ORDER 6102</a> MADE IT A CRIME TO HOLD GOLD.\n\nCITIZENS WERE FORCED TO TURN IN THEIR GOLD IN EXCHANGE FOR PAPER DOLLARS.";
|
||
document.getElementById('next4b').style.cssText = '';
|
||
showNextBtn('next4b');
|
||
document.getElementById('sources4b').style.cssText = '';
|
||
showNextBtn('sources4b');
|
||
} else if (si===2) {
|
||
txt.innerHTML = "AFTER FORCING PEOPLE TO TURN IN THEIR GOLD, THE GOVERNMENT PASSED THE <a href=\"https://www.federalreservehistory.org/essays/gold-reserve-act\" target=\"_blank\" style=\"text-decoration:underline;font-weight:bold;color:#00ff00\">THE 1934 GOLD RESERVE ACT</a> AND GAVE THE U.S. TREASURY CONTROL OF THE GOLD.\n\nPEOPLE WERE PAID $20.67/OZ. THE GOVT THEN REVALUED GOLD TO $35/OZ.\n\n";
|
||
s4.querySelector('.s4visual').innerHTML='<div class="callout-box">⚠ $20.67/OZ → $35/OZ = 69% STOLEN OVERNIGHT ⚠</div>';
|
||
s4.querySelector('.s4visual').classList.add('visible');
|
||
document.getElementById('next4c').style.cssText = '';
|
||
showNextBtn('next4c');
|
||
document.getElementById('sources4c').style.cssText = '';
|
||
showNextBtn('sources4c');
|
||
} else if (si===3) {
|
||
txt.innerHTML = "THE PAPER DOLLAR COULD STILL BE EXCHANGED FOR GOLD, BUT ON <a href=\"https://www.federalreservehistory.org/essays/gold-convertibility-ends\" target=\"_blank\" style=\"text-decoration:underline;font-weight:bold;color:#00ff00\">1971, PRESIDENT NIXON REMOVED THAT OPTION</a>, THE PRICE OF GOLD SURGED TO $835-850/OZ.\n\nTHE DOLLAR LOST 96% OF ITS PURCHASING POWER AGAINST REAL MONEY.\n\n";
|
||
let html='<div style="text-align:center;font-size:0.8rem;color:#007700;margin-bottom:0.5rem;">VALUE OF $1 SINCE 1971</div><div class="coin-grid">';
|
||
for(let i=0;i<100;i++) html+='<div class="coin '+(i<4?'gold':'')+'"></div>';
|
||
html+='</div><div style="text-align:center;margin-top:0.5rem;font-size:0.75rem;color:#00ff00;">~96% PURCHASING POWER LOST</div>';
|
||
s4.querySelector('.s4visual').innerHTML=html;
|
||
s4.querySelector('.s4visual').classList.add('visible');
|
||
document.getElementById('next4d').style.cssText = '';
|
||
showNextBtn('next4d');
|
||
document.getElementById('sources4d').style.cssText = '';
|
||
showNextBtn('sources4d');
|
||
} else if (si===4) {
|
||
txt.innerHTML = "BITCOIN HAS BEEN CALLED <a href=\"https://www.forbes.com/sites/digital-assets/2024/12/08/us-treasury-names-bitcoin-digital-gold-after-price-explosion/\" target=\"_blank\" style=\"text-decoration:underline;font-weight:bold;color:#00ff00\">DIGITAL GOLD</a>. BUT UNLIKE GOLD, NO ONE CAN TOUCH THIS.";
|
||
s4.querySelector('.s4visual').innerHTML=
|
||
'<table class="comp-table"><tr><th></th><th>GOLD</th><th>BITCOIN</th></tr>'
|
||
+'<tr><td>CONFISCATABLE?</td><td class="yes">✅ YES (1933)</td><td class="no">❌ NO</td></tr>'
|
||
+'<tr><td>PRINTABLE?</td><td class="no">❌ NO</td><td class="no">❌ NO</td></tr>'
|
||
+'<tr><td>UNCENSORABLE?</td><td class="no">❌ NO</td><td class="yes">✅ YES</td></tr>'
|
||
+'<tr><td>SUPPLY CAP?</td><td class="no">❌ NO</td><td class="yes">✅ 21M</td></tr>'
|
||
+'<tr><td>TRUST MODEL</td><td>GOVERNMENT</td><td>CODE</td></tr>'
|
||
+'</table>'
|
||
+'<div class="punch-row">'
|
||
+'<div class="punch-card"><span class="punch-icon">🚫</span><span class="punch-text">NO PRESIDENT<br>CAN BAN IT</span></div>'
|
||
+'<div class="punch-card"><span class="punch-icon">🚫</span><span class="punch-text">NO CONGRESS<br>CAN INFLATE IT</span></div>'
|
||
+'<div class="punch-card"><span class="punch-icon">🚫</span><span class="punch-text">NO BANK<br>CAN FREEZE IT</span></div>'
|
||
+'</div>';
|
||
s4.querySelector('.s4visual').classList.add('visible');
|
||
document.getElementById('next4e').style.cssText = '';
|
||
showNextBtn('next4e');
|
||
document.getElementById('sources4e').style.cssText = '';
|
||
showNextBtn('sources4e');
|
||
}
|
||
}
|
||
}
|
||
|
||
// Scene 5 skip
|
||
const s5 = document.getElementById('scene5');
|
||
if (s5.style.display === 'flex') {
|
||
s5c.forEach(t => clearTimeout(t)); s5c = [];
|
||
const txt = document.getElementById('s5Text');
|
||
const vis = document.getElementById('s5Visual');
|
||
txt.innerHTML = "BITCOIN HAS NO TRUE COMPETITORS AS SOUND MONEY.\n\nBUT SEVERAL COINS COMPETE IN DIFFERENT NICHES — PRIVACY, SPEED, PROGRAMMABILITY, OR STORE-OF-VALUE NARRATIVES.\n\nNONE POSSESS BITCOIN'S FULL SET OF PROPERTIES.\n\nTHE NETWORK EFFECT IS INSURMOUNTABLE.\n\nHERE IS THE HONEST COMPARISON.";
|
||
vis.innerHTML='<table class="comp-table" id="s5table"><tr><th></th><th class="btc-col">BTC</th><th>ETH</th><th>XMR</th><th>XRP</th><th>SOL</th></tr>'
|
||
+'<tr><td>NICHE</td><td class="btc-col"><span class="nickname">SOUND MONEY</span></td><td>PROGRAMMABILITY</td><td>PRIVACY</td><td>PAYMENTS</td><td>SPEED</td></tr>'
|
||
+'<tr><td>DECENTRALIZED?</td><td class="btc-col">✅ YES</td><td>⚠️ PARTIAL</td><td>✅ YES</td><td>❌ RIPPLE LABS</td><td>❌ VC/FOUNDATION</td></tr>'
|
||
+'<tr><td>FAIR LAUNCH?</td><td class="btc-col">✅ YES</td><td>❌ 72M PREMINE</td><td>✅ YES</td><td>❌ 100% PREMINE</td><td>❌ PREMINE</td></tr>'
|
||
+'<tr><td>SUPPLY CAP</td><td class="btc-col">✅ 21M</td><td>❌ NO CAP</td><td>❌ TAIL EMISSION</td><td>❌ NO CAP</td><td>❌ NO CAP</td></tr>'
|
||
+'<tr><td>UNCENSORABLE?</td><td class="btc-col">✅ YES</td><td>❌ NO</td><td>✅ YES</td><td>❌ NO</td><td>❌ NO</td></tr>'
|
||
+'</table>'
|
||
+'<div class="punch-row">'
|
||
+'<div class="punch-card"><span class="punch-icon">🏆</span><span class="punch-text">FIRST —<br>EVERYTHING ELSE IS A COPY</span></div>'
|
||
+'<div class="punch-card"><span class="punch-icon">🔒</span><span class="punch-text">MOST SECURE —<br>MOST HASH POWER BY FAR</span></div>'
|
||
+'<div class="punch-card"><span class="punch-icon">🧪</span><span class="punch-text">TRULY DECENTRALIZED —<br>NO FOUNDER, NO COMPANY, NO CEO</span></div>'
|
||
+'</div>';
|
||
vis.classList.add('visible');
|
||
document.getElementById('returnFromScene5').style.cssText='';
|
||
showNextBtn('returnFromScene5');
|
||
document.getElementById('sources5').style.cssText='';
|
||
showNextBtn('sources5');
|
||
}
|
||
|
||
// Scene 7 skip
|
||
const s7 = document.getElementById('scene7');
|
||
if (s7.style.display === 'flex') {
|
||
s7c.forEach(t => clearTimeout(t)); s7c = [];
|
||
const txt = document.getElementById('s7Text');
|
||
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.";
|
||
const canvasDiv = document.getElementById('s7Canvas');
|
||
canvasDiv.classList.add('visible');
|
||
if (deskAnimId) { cancelAnimationFrame(deskAnimId); deskAnimId = null; }
|
||
if (exfilDeskAnimId) { cancelAnimationFrame(exfilDeskAnimId); exfilDeskAnimId = null; }
|
||
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
|
||
const s8 = document.getElementById('scene8');
|
||
if (s8.style.display === 'flex') {
|
||
s8c.forEach(t => clearTimeout(t)); s8c = [];
|
||
const txt = document.getElementById('s8Text');
|
||
txt.innerHTML = "YOUR PHONE IS LITERALLY A TRACKING DEVICE IN YOUR POCKET — UNLESS YOU CHOOSE OTHERWISE.\n\nGRAPHENEOS LOCKS DOWN EVERY SENSOR AND PERMISSION — CLICK A TAB TO SEE THE DIFFERENCE.";
|
||
const canvasDiv = document.getElementById('s8Canvas');
|
||
canvasDiv.classList.add('visible');
|
||
if (phoneAnimId) { cancelAnimationFrame(phoneAnimId); phoneAnimId = null; }
|
||
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
|
||
initPhoneScene();
|
||
drawPhoneScene();
|
||
const s8Row = document.getElementById('s8BtnRow');
|
||
s8Row.style.cssText = '';
|
||
s8Row.style.visibility = 'visible';
|
||
s8Row.style.opacity = '1';
|
||
s8Row.style.pointerEvents = 'auto';
|
||
}
|
||
|
||
// Scene 9 skip
|
||
const s9 = document.getElementById('scene9');
|
||
if (s9.style.display === 'flex') {
|
||
s9c.forEach(t => clearTimeout(t)); s9c = [];
|
||
const txt = document.getElementById('s9Text');
|
||
txt.innerHTML = "THE INTERNET WAS DESIGNED TO BE DECENTRALIZED — BUT ISPS HAVE TURNED IT INTO A UTILITY CONTROLLED BY GATEKEEPERS.\n\nMESH NETWORKS AND P2P PROTOCOLS LET COMMUNITIES BUILD THEIR OWN INTERNET — NO ISP REQUIRED.";
|
||
const canvasDiv = document.getElementById('s9Canvas');
|
||
canvasDiv.classList.add('visible');
|
||
if (meshAnimId) { cancelAnimationFrame(meshAnimId); meshAnimId = null; }
|
||
initMesh();
|
||
drawMesh();
|
||
document.getElementById('returnFromScene9').style.cssText='';
|
||
showNextBtn('returnFromScene9');
|
||
}
|
||
|
||
// Scene 8b skip
|
||
const s8b = document.getElementById('scene8b');
|
||
if (s8b.style.display === 'flex') {
|
||
s8bc.forEach(t => clearTimeout(t)); s8bc = [];
|
||
const txt = document.getElementById('s8bText');
|
||
txt.innerHTML = "EACH TIME YOUR PHONE SENDS DATA TO THIRD-PARTY SERVERS, IT CREATES A DIGITAL PROFILE OF YOU — SOLD TO THE HIGHEST BIDDER.\n\nCLICK THE TABS TO SEE WHERE YOUR DATA ACTUALLY GOES.";
|
||
const canvasDiv = document.getElementById('s8bCanvas');
|
||
canvasDiv.classList.add('visible');
|
||
if (exfilAnimId) { cancelAnimationFrame(exfilAnimId); exfilAnimId = null; }
|
||
initExfilScene();
|
||
drawExfilScene();
|
||
window._exfilDone = true;
|
||
document.getElementById('returnFromScene8b').style.cssText='';
|
||
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');
|
||
}
|
||
|
||
}
|
||
|
||
if (e.key === 'Delete') {
|
||
// Fast-forward to Scene 2
|
||
document.getElementById('matrixCanvas').style.display = 'none';
|
||
document.getElementById('textContainer').style.display = 'none';
|
||
document.getElementById('followBtn').style.display = 'none';
|
||
|
||
loadScene2(document.getElementById('scene2'));
|
||
}
|
||
});
|
||
|
||
</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 (~$90–100/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>
|
||
<li><a href="https://www.gold.org/sites/default/files/documents/1900mar14.pdf" target="_blank">Gold Standard Act of 1900 (PDF), World Gold Council.</a></li>
|
||
<li><a href="https://www.usmoneyreserve.com/resources/videos/transcripts/executive-order-6102-did-you-know/" target="_blank">Executive Order 6102 — U.S. Money Reserve.</a></li>
|
||
<li><a href="https://www.federalreservehistory.org/essays/gold-reserve-act" target="_blank">Gold Reserve Act of 1934 — Federal Reserve History.</a></li>
|
||
<li><a href="https://www.federalreservehistory.org/essays/gold-convertibility-ends" target="_blank">Nixon Ends Gold Convertibility (1971) — Federal Reserve History.</a></li>
|
||
<li><a href="https://www.forbes.com/sites/digital-assets/2024/12/08/us-treasury-names-bitcoin-digital-gold-after-price-explosion/" target="_blank">U.S. Treasury Names Bitcoin 'Digital Gold' — Forbes.</a></li>
|
||
<li><a href="https://ncbi.nlm.nih.gov/pmc/articles/PMC2567554/" target="_blank">Flexner, A. (1910). Medical Education in the United States and Canada. Carnegie Foundation Bulletin No. 4.</a> — The original Flexner Report that evaluated 155 medical schools and led to closure of half of them.</li>
|
||
<li><a href="https://jamanetwork.com/journals/jama/article-abstract/198677" target="_blank">Beck, A.H. (2004). "The Flexner Report and the Standardization of American Medical Education." JAMA. 291(17):2139-2140.</a> — Analysis of Flexner's impact on medical standardization and its disproportionate effect on women and minority doctors.</li>
|
||
<li><a href="https://www.ama-assn.org/about/ama-history/ama-history" target="_blank">American Medical Association — AMA history.</a> — AMA's Council on Medical Education commissioned and supported the Flexner Report; AMA set licensing standards that became law.</li>
|
||
<li><a href="https://www.fda.gov/about-fda/histories-product-regulation/sulfanilamide-disaster" target="_blank">FDA — The Sulfanilamide Disaster (1937).</a> — 107 deaths from Elixir Sulfanilamide (diethylene glycol poisoning) that triggered the 1938 Food, Drug & Cosmetic Act.</li>
|
||
<li><a href="https://www.fda.gov/about-fda/changes-science-law-and-regulatory-authorities/part-ii-1938-food-drug-cosmetic-act" target="_blank">FDA — Part II: 1938, Food, Drug & Cosmetic Act.</a> — New law required pre-market safety proof for all drugs, giving FDA broad regulatory power.</li>
|
||
<li><a href="https://www.cms.gov/data-research/statistics-trends-and-reports/national-health-expenditure-data/historical" target="_blank">CMS — National Health Expenditure Accounts (Historical).</a> — Official U.S. health spending estimates from 1960; shows pre-Medicare spending of ~$41B in 1965 and growth to $4.5T+ by 2022.</li>
|
||
<li><a href="https://www.cms.gov/data-research/statistics-trends-and-reports/national-health-expenditure-data/nhe-fact-sheet" target="_blank">CMS — NHE Fact Sheet (2024).</a> — U.S. health spending reached $5.3T in 2024, up from $27B in 1960 — a 100x increase driven partly by Medicare/Medicaid third-party payer system.</li>
|
||
<li><a href="https://www.congress.gov/93/statute/STATUTE-87/STATUTE-87-Pg914.pdf" target="_blank">Health Maintenance Organization Act of 1973 (Pub.L. 93-222).</a> — Original statute that formalized managed care, mandated employer dual-choice, and replaced the doctor-patient relationship with the corporate provider-member model.</li>
|
||
<li><a href="https://en.wikipedia.org/wiki/Health_Maintenance_Organization_Act_of_1973" target="_blank">Wikipedia — Health Maintenance Organization Act of 1973.</a> — Nixon administration, Dr. Paul Ellwood's "less care = more money" incentive structure, and the HMO market transformation.</li>
|
||
<li><a href="https://syntropy.institute/" target="_blank">Syntropy Institute.</a> — Open infrastructure for decentralized, patient-controlled medicine — biohacking, functional medicine, and direct-to-consumer health data ownership.</li>
|
||
</ol>
|
||
<div class="refs-back"><button id="refsBackBtn" onclick="document.getElementById('sceneRefs').classList.remove('visible');var c=window.refsCaller;if(c==='scene7b'||c==='scene8b'||c==='scene4a'||c==='scene4b'||c==='scene4c'||c==='scene4d'||c==='scene4e'||c==='scene5'||c==='scene10a'||c==='scene10b'||c==='scene10c'||c==='scene10d'||c==='scene10e'||c==='scene11')document.getElementById(c).style.display='flex';window.refsCaller=null;">BACK</button></div>
|
||
</div>
|
||
</div>
|
||
|
||
</body>
|
||
</html>
|