forked from avi/signalelsewhere
2772 lines
120 KiB
HTML
2772 lines
120 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;
|
|
}
|
|
|
|
/* 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 */
|
|
.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; }
|
|
</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>
|
|
<button class="btnNext" id="next4a">NEXT</button>
|
|
</div>
|
|
<div id="scene4b" class="scene scene4sub">
|
|
<div class="s4tl"></div>
|
|
<div class="scene4text" id="s4bText"></div>
|
|
<div class="s4visual" id="s4bVisual"></div>
|
|
<button class="btnNext" id="next4b">NEXT</button>
|
|
</div>
|
|
<div id="scene4c" class="scene scene4sub">
|
|
<div class="s4tl"></div>
|
|
<div class="scene4text" id="s4cText"></div>
|
|
<div class="s4visual" id="s4cVisual"></div>
|
|
<button class="btnNext" id="next4c">NEXT</button>
|
|
</div>
|
|
<div id="scene4d" class="scene scene4sub">
|
|
<div class="s4tl"></div>
|
|
<div class="scene4text" id="s4dText"></div>
|
|
<div class="s4visual" id="s4dVisual"></div>
|
|
<button class="btnNext" id="next4d">NEXT</button>
|
|
</div>
|
|
<div id="scene4e" class="scene scene4sub">
|
|
<div class="s4tl"></div>
|
|
<div class="scene4text" id="s4eText"></div>
|
|
<div class="s4visual" id="s4eVisual"></div>
|
|
<button class="btnNext" id="next4e">NEXT</button>
|
|
</div>
|
|
|
|
<div id="scene5" class="scene">
|
|
<div class="scene5text" id="s5Text"></div>
|
|
<div class="s5visual" id="s5Visual"></div>
|
|
<button class="btnNext" id="returnFromScene5">RETURN</button>
|
|
</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">
|
|
<div class="scene7text" id="s7Text"></div>
|
|
<div class="s7visual" id="s7Visual"></div>
|
|
<button class="btnNext" id="returnFromScene7">RETURN</button>
|
|
</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>
|
|
<button class="btnNext" id="returnFromScene8b">RETURN</button>
|
|
</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>
|
|
|
|
<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:5.5rem;margin-bottom:2rem;text-align:center;';
|
|
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 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. THAT'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');
|
|
},undefined,undefined,s4c);
|
|
},undefined,undefined,s4c);
|
|
},1500);
|
|
s4c.push(t1);
|
|
},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. CITIZENS WERE FORCED TO TURN IN THEIR GOLD IN EXCHANGE FOR PAPER DOLLARS.",()=>{
|
|
showNextBtn('next4b');
|
|
},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');
|
|
},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');
|
|
},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');
|
|
},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');
|
|
},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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
function loadScene7(sceneElem) {
|
|
s7c=[];
|
|
sceneElem.style.display='flex';
|
|
const txt=document.getElementById('s7Text');
|
|
const vis=document.getElementById('s7Visual');
|
|
txt.innerHTML='';
|
|
vis.className='s7visual';
|
|
let o=0;
|
|
const fi=setInterval(()=>{
|
|
if (sceneElem.style.display !== 'flex' || document.getElementById('returnFromScene7').style.visibility === 'visible') { clearInterval(fi); return; }
|
|
o+=0.05;if(o>=1){o=1;clearInterval(fi);
|
|
typeCalmly(txt,"DESKTOP COMPUTING IS DOMINATED BY CORPORATIONS THAT MONETIZE YOUR DATA AND RESTRICT YOUR FREEDOM.",()=>{
|
|
const t1=setTimeout(()=>{
|
|
txt.innerHTML+="\n\n";
|
|
vis.classList.add('visible');
|
|
vis.innerHTML=buildS6DesktopTable();
|
|
typeCalmly(txt,"LINUX IS THE ONLY OS THAT RESPECTS YOUR FREEDOM — BECAUSE IT'S BUILT BY THE COMMUNITY, NOT A CORPORATION.",()=>{
|
|
const t3=setTimeout(()=>{
|
|
document.getElementById('returnFromScene7').style.cssText='';
|
|
showNextBtn('returnFromScene7');
|
|
},400);
|
|
s7c.push(t3);
|
|
},8,20,s7c);
|
|
},300);
|
|
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, 3).map(d => d.node.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 s2c = [];
|
|
let s7c = [];
|
|
let s8c = [];
|
|
let s9c = [];
|
|
let s8bc = [];
|
|
|
|
// 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: 1200, color: '#ff4444', status: 'GOOGLE AND THIRD-PARTY APPS COLLECT YOUR DATA BY DEFAULT. YOU ARE THE PRODUCT.' },
|
|
ios: { label: 'iOS', counterMax: 600, color: '#ffff00', status: 'APPLE COLLECTS DATA THROUGH ITS SERVICES. SOME THIRD-PARTY TRACKING IS BLOCKED.' },
|
|
};
|
|
|
|
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;
|
|
|
|
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;
|
|
}
|
|
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);
|
|
}
|
|
|
|
// Initialize on load
|
|
window.addEventListener('load', () => {
|
|
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('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').textContent = "IS AN INCUBATOR THAT HAS MANY DECENTRALIZED STARTUPS UNDERNEATH IT\n\n\n\n\nWE BELIEVE EVERYTHING SHOULD BE DECENTRALIZED";
|
|
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('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').textContent = "IS AN INCUBATOR THAT HAS MANY DECENTRALIZED STARTUPS UNDERNEATH IT\n\n\n\n\nWE BELIEVE EVERYTHING SHOULD BE DECENTRALIZED";
|
|
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; }
|
|
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('exfilCanvas').addEventListener('click', (e) => {
|
|
handleExfilCanvasClick(e.clientX, e.clientY);
|
|
});
|
|
|
|
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('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') {
|
|
// 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').textContent =
|
|
"IS AN INCUBATOR THAT HAS MANY DECENTRALIZED STARTUPS UNDERNEATH IT\n\n\n\n\nWE BELIEVE EVERYTHING SHOULD BE DECENTRALIZED";
|
|
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. THAT'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');
|
|
} 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. CITIZENS WERE FORCED TO TURN IN THEIR GOLD IN EXCHANGE FOR PAPER DOLLARS.";
|
|
document.getElementById('next4b').style.cssText = '';
|
|
showNextBtn('next4b');
|
|
} 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');
|
|
} 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');
|
|
} 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');
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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');
|
|
}
|
|
|
|
// Scene 7 skip
|
|
const s7 = document.getElementById('scene7');
|
|
if (s7.style.display === 'flex') {
|
|
s7c.forEach(t => clearTimeout(t)); s7c = [];
|
|
const txt = document.getElementById('s7Text');
|
|
const vis = document.getElementById('s7Visual');
|
|
txt.innerHTML = "DESKTOP COMPUTING IS DOMINATED BY CORPORATIONS THAT MONETIZE YOUR DATA AND RESTRICT YOUR FREEDOM.\n\nLINUX IS THE ONLY OS THAT RESPECTS YOUR FREEDOM — BECAUSE IT'S BUILT BY THE COMMUNITY, NOT A CORPORATION.";
|
|
vis.innerHTML=buildS6DesktopTable();
|
|
vis.classList.add('visible');
|
|
document.getElementById('returnFromScene7').style.cssText='';
|
|
showNextBtn('returnFromScene7');
|
|
}
|
|
|
|
// 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();
|
|
document.getElementById('returnFromScene8b').style.cssText='';
|
|
showNextBtn('returnFromScene8b');
|
|
}
|
|
|
|
}
|
|
|
|
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>
|
|
</body>
|
|
</html>
|