+
// WHAT YOU GET
+
+
+
₹3L+
+
IN PRIZES
+
ACROSS BOTH TRACKS
+
+
+
24H
+
FOOD & CAFFEINE
+
+
+
+
+
SWAG + CERTS + WIFI + VIBES
+
EVERYTHING ELSE IS ON US
+
+
+
+
+
+
+
+
+
+
+
// TIMELINE
+
+
+
+
MAR 15
+
REGISTRATION OPENS
+
+
+
+
APR 08
+
REGISTRATION CLOSES
+
+
+
+
APR 11
+
OPENING CEREMONY
+
+
+
+
APR 11-12
+
24 HOURS OF HACKING
+
+
+
+
APR 12
+
DEMOS & JUDGING
+
+
+
+
APR 12
+
+ CLOSING CEREMONY & PRIZES
+
+
+
+
+
+
+
+
+
+
// FAQ
+
+
+
+ WHO CAN PARTICIPATE?
+ +
+
+
+ Anyone with a passion for building. Students,
+ professionals, hobbyists — if you can code, design,
+ or pitch, you're in. Teams of 2-4 members.
+
+
+
+
+ DO I NEED A TEAM?
+ +
+
+
+ You can register solo and find teammates at our team
+ formation event on March 1st. Or bring your own
+ squad. Max team size is 4.
+
+
+
+
+ WHAT SHOULD I BUILD?
+ +
+
+
+ Anything that fits within our two tracks: NEXUS
+ (AI/ML) or SPECTRA (Web3). We value creativity,
+ technical depth, and real-world impact.
+
+
+
+
+ IS IT FREE?
+ +
+
+
+ Yes. Hack X is completely free. We provide the
+ venue, food, WiFi, mentors, and ₹3L+ in prizes. You
+ bring the code.
+
+
+
+
+ WHAT DO I NEED TO BRING?
+ +
+
+
+ Your laptop, charger, and an unhinged desire to
+ build something amazing in 24 hours. We handle the
+ rest.
+
+
+
+
+
+
+
+
+
+
// THE TEAM
+
+ 36 people behind the scenes making Hack X happen. CodeCell's
+ finest.
+
+
+ 36
+ ORGANIZERS
+
+
+ DEPARTMENT HEADS // SEVERED FLOOR
+
+
+
MACRODATA REFINEMENT // O&D
+
+
OPTICS & DESIGN // WELLNESS
+
+
NEW INNIES // PROBATIONARY
+
+
THE HUMANS BEHIND THE TERMINAL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
STOP MUSIC
+
+
+
INITIALIZING HACK X...
+
+
+
\ No newline at end of file
diff --git a/hackx/macrodata.js b/hackx/macrodata.js
new file mode 100644
index 00000000..3766743c
--- /dev/null
+++ b/hackx/macrodata.js
@@ -0,0 +1,57 @@
+const emptyBins = [
+ {WO: 0, FC: 0, DR: 0, MA: 0},
+ {WO: 0, FC: 0, DR: 0, MA: 0},
+ {WO: 0, FC: 0, DR: 0, MA: 0},
+ {WO: 0, FC: 0, DR: 0, MA: 0},
+ {WO: 0, FC: 0, DR: 0, MA: 0}
+];
+
+class MacrodataFile {
+ constructor() {
+ this.localStorageKey = 'hackx-data';
+ const file = JSON.parse(localStorage.getItem(this.localStorageKey)) ?? this.assignFile();
+ this.fileName = file.fileName;
+ this.storedBins = file.storedBins;
+ this.coordinates = file.coordinates;
+ }
+
+ assignFile() {
+ const names = HACKX_CONFIG.projectNames;
+ const allButPrevious = names.filter(f => f !== this.fileName);
+ const fileName = allButPrevious[Math.floor(Math.random() * allButPrevious.length)];
+ const coordinates = this.#generateCoordinates();
+ const macrodata = {
+ fileName,
+ storedBins: emptyBins,
+ coordinates
+ };
+ localStorage.setItem(this.localStorageKey, JSON.stringify(macrodata));
+ return macrodata;
+ }
+
+ updateProgress(bins) {
+ const updatedFile = {
+ fileName: this.fileName,
+ storedBins: bins,
+ coordinates: this.coordinates
+ };
+ localStorage.setItem(this.localStorageKey, JSON.stringify(updatedFile));
+ }
+
+ resetFile() {
+ localStorage.removeItem(this.localStorageKey);
+ const file = this.assignFile();
+ this.fileName = file.fileName;
+ this.storedBins = file.storedBins;
+ this.coordinates = file.coordinates;
+ }
+
+ #generateCoordinates() {
+ function randHex() {
+ return floor(random(0, 256)).toString(16).toUpperCase().padStart(2, '0');
+ }
+ let x = randHex() + randHex() + randHex();
+ let y = randHex() + randHex() + randHex();
+ return `0x${x} : 0x${y}`;
+ }
+}
diff --git a/hackx/manifest.json b/hackx/manifest.json
new file mode 100644
index 00000000..41906f14
--- /dev/null
+++ b/hackx/manifest.json
@@ -0,0 +1,18 @@
+{
+ "$schema": "https://json.schemastore.org/web-manifest-combined.json",
+ "name": "HACK X // CodeCell",
+ "short_name": "HackX",
+ "start_url": "/",
+ "display": "standalone",
+ "Scope": "/",
+ "background_color": "#0a1628",
+ "theme_color": "#4fd1d9",
+ "description": "HACK X — Where Code Meets Chaos",
+ "icons": [
+ {
+ "src": "images/icon.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ }
+ ]
+}
diff --git a/hackx/osn.js b/hackx/osn.js
new file mode 100644
index 00000000..15235f11
--- /dev/null
+++ b/hackx/osn.js
@@ -0,0 +1,602 @@
+// Plain JS version of Josh Forisha's implementation of opensimplex noise
+// https://github.com/joshforisha/open-simplex-noise-js
+// This version is currently posted here https://gist.github.com/PARC6502/85c99c04c9b3c6ae52c3c27605b4df0a
+// Will probably be cleaned up and have its own repo, at some point...
+
+'use strict';
+var OpenSimplexNoise;
+
+(function () {
+ var constants_1 = {
+ NORM_2D: 1.0 / 47.0,
+ NORM_3D: 1.0 / 103.0,
+ NORM_4D: 1.0 / 30.0,
+ SQUISH_2D: (Math.sqrt(2 + 1) - 1) / 2,
+ SQUISH_3D: (Math.sqrt(3 + 1) - 1) / 3,
+ SQUISH_4D: (Math.sqrt(4 + 1) - 1) / 4,
+ STRETCH_2D: (1 / Math.sqrt(2 + 1) - 1) / 2,
+ STRETCH_3D: (1 / Math.sqrt(3 + 1) - 1) / 3,
+ STRETCH_4D: (1 / Math.sqrt(4 + 1) - 1) / 4,
+ base2D: [
+ [1, 1, 0, 1, 0, 1, 0, 0, 0],
+ [1, 1, 0, 1, 0, 1, 2, 1, 1],
+ ],
+ base3D: [
+ [0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1],
+ [2, 1, 1, 0, 2, 1, 0, 1, 2, 0, 1, 1, 3, 1, 1, 1],
+ [1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 2, 1, 1, 0, 2, 1, 0, 1, 2, 0, 1, 1],
+ ],
+ base4D: [
+ [
+ 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0,
+ 1,
+ ],
+ [
+ 3, 1, 1, 1, 0, 3, 1, 1, 0, 1, 3, 1, 0, 1, 1, 3, 0, 1, 1, 1, 4, 1, 1, 1,
+ 1,
+ ],
+ [
+ 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 2, 1, 1, 0,
+ 0, 2, 1, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 1, 0, 2, 0, 1, 0, 1, 2, 0, 0,
+ 1, 1,
+ ],
+ [
+ 3, 1, 1, 1, 0, 3, 1, 1, 0, 1, 3, 1, 0, 1, 1, 3, 0, 1, 1, 1, 2, 1, 1, 0,
+ 0, 2, 1, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 1, 0, 2, 0, 1, 0, 1, 2, 0, 0,
+ 1, 1,
+ ],
+ ],
+ gradients2D: [5, 2, 2, 5, -5, 2, -2, 5, 5, -2, 2, -5, -5, -2, -2, -5],
+ gradients3D: [
+ -11, 4, 4, -4, 11, 4, -4, 4, 11, 11, 4, 4, 4, 11, 4, 4, 4, 11, -11, -4, 4,
+ -4, -11, 4, -4, -4, 11, 11, -4, 4, 4, -11, 4, 4, -4, 11, -11, 4, -4, -4,
+ 11, -4, -4, 4, -11, 11, 4, -4, 4, 11, -4, 4, 4, -11, -11, -4, -4, -4, -11,
+ -4, -4, -4, -11, 11, -4, -4, 4, -11, -4, 4, -4, -11,
+ ],
+ gradients4D: [
+ 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, -3, 1, 1, 1, -1, 3, 1, 1,
+ -1, 1, 3, 1, -1, 1, 1, 3, 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3, 1, 1, -1, 1,
+ 3, -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3, 3, 1, -1, 1, 1,
+ 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3, -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3,
+ 1, -1, 1, -1, 3, 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3,
+ -3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3, 3, 1, 1, -1,
+ 1, 3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3, -3, 1, 1, -1, -1, 3, 1, -1, -1, 1,
+ 3, -1, -1, 1, 1, -3, 3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3, -1, 1, -1, 1,
+ -3, -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3, 3, 1, -1,
+ -1, 1, 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3, -3, 1, -1, -1, -1, 3, -1,
+ -1, -1, 1, -3, -1, -1, 1, -1, -3, 3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3,
+ -1, 1, -1, -1, -3, -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3, -1, -1, -1,
+ -1, -3,
+ ],
+ lookupPairs2D: [
+ 0, 1, 1, 0, 4, 1, 17, 0, 20, 2, 21, 2, 22, 5, 23, 5, 26, 4, 39, 3, 42, 4,
+ 43, 3,
+ ],
+ lookupPairs3D: [
+ 0, 2, 1, 1, 2, 2, 5, 1, 6, 0, 7, 0, 32, 2, 34, 2, 129, 1, 133, 1, 160, 5,
+ 161, 5, 518, 0, 519, 0, 546, 4, 550, 4, 645, 3, 647, 3, 672, 5, 673, 5,
+ 674, 4, 677, 3, 678, 4, 679, 3, 680, 13, 681, 13, 682, 12, 685, 14, 686,
+ 12, 687, 14, 712, 20, 714, 18, 809, 21, 813, 23, 840, 20, 841, 21, 1198,
+ 19, 1199, 22, 1226, 18, 1230, 19, 1325, 23, 1327, 22, 1352, 15, 1353, 17,
+ 1354, 15, 1357, 17, 1358, 16, 1359, 16, 1360, 11, 1361, 10, 1362, 11,
+ 1365, 10, 1366, 9, 1367, 9, 1392, 11, 1394, 11, 1489, 10, 1493, 10, 1520,
+ 8, 1521, 8, 1878, 9, 1879, 9, 1906, 7, 1910, 7, 2005, 6, 2007, 6, 2032, 8,
+ 2033, 8, 2034, 7, 2037, 6, 2038, 7, 2039, 6,
+ ],
+ lookupPairs4D: [
+ 0, 3, 1, 2, 2, 3, 5, 2, 6, 1, 7, 1, 8, 3, 9, 2, 10, 3, 13, 2, 16, 3, 18,
+ 3, 22, 1, 23, 1, 24, 3, 26, 3, 33, 2, 37, 2, 38, 1, 39, 1, 41, 2, 45, 2,
+ 54, 1, 55, 1, 56, 0, 57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 256,
+ 3, 258, 3, 264, 3, 266, 3, 272, 3, 274, 3, 280, 3, 282, 3, 2049, 2, 2053,
+ 2, 2057, 2, 2061, 2, 2081, 2, 2085, 2, 2089, 2, 2093, 2, 2304, 9, 2305, 9,
+ 2312, 9, 2313, 9, 16390, 1, 16391, 1, 16406, 1, 16407, 1, 16422, 1, 16423,
+ 1, 16438, 1, 16439, 1, 16642, 8, 16646, 8, 16658, 8, 16662, 8, 18437, 6,
+ 18439, 6, 18469, 6, 18471, 6, 18688, 9, 18689, 9, 18690, 8, 18693, 6,
+ 18694, 8, 18695, 6, 18696, 9, 18697, 9, 18706, 8, 18710, 8, 18725, 6,
+ 18727, 6, 131128, 0, 131129, 0, 131130, 0, 131131, 0, 131132, 0, 131133,
+ 0, 131134, 0, 131135, 0, 131352, 7, 131354, 7, 131384, 7, 131386, 7,
+ 133161, 5, 133165, 5, 133177, 5, 133181, 5, 133376, 9, 133377, 9, 133384,
+ 9, 133385, 9, 133400, 7, 133402, 7, 133417, 5, 133421, 5, 133432, 7,
+ 133433, 5, 133434, 7, 133437, 5, 147510, 4, 147511, 4, 147518, 4, 147519,
+ 4, 147714, 8, 147718, 8, 147730, 8, 147734, 8, 147736, 7, 147738, 7,
+ 147766, 4, 147767, 4, 147768, 7, 147770, 7, 147774, 4, 147775, 4, 149509,
+ 6, 149511, 6, 149541, 6, 149543, 6, 149545, 5, 149549, 5, 149558, 4,
+ 149559, 4, 149561, 5, 149565, 5, 149566, 4, 149567, 4, 149760, 9, 149761,
+ 9, 149762, 8, 149765, 6, 149766, 8, 149767, 6, 149768, 9, 149769, 9,
+ 149778, 8, 149782, 8, 149784, 7, 149786, 7, 149797, 6, 149799, 6, 149801,
+ 5, 149805, 5, 149814, 4, 149815, 4, 149816, 7, 149817, 5, 149818, 7,
+ 149821, 5, 149822, 4, 149823, 4, 149824, 37, 149825, 37, 149826, 36,
+ 149829, 34, 149830, 36, 149831, 34, 149832, 37, 149833, 37, 149842, 36,
+ 149846, 36, 149848, 35, 149850, 35, 149861, 34, 149863, 34, 149865, 33,
+ 149869, 33, 149878, 32, 149879, 32, 149880, 35, 149881, 33, 149882, 35,
+ 149885, 33, 149886, 32, 149887, 32, 150080, 49, 150082, 48, 150088, 49,
+ 150098, 48, 150104, 47, 150106, 47, 151873, 46, 151877, 45, 151881, 46,
+ 151909, 45, 151913, 44, 151917, 44, 152128, 49, 152129, 46, 152136, 49,
+ 152137, 46, 166214, 43, 166215, 42, 166230, 43, 166247, 42, 166262, 41,
+ 166263, 41, 166466, 48, 166470, 43, 166482, 48, 166486, 43, 168261, 45,
+ 168263, 42, 168293, 45, 168295, 42, 168512, 31, 168513, 28, 168514, 31,
+ 168517, 28, 168518, 25, 168519, 25, 280952, 40, 280953, 39, 280954, 40,
+ 280957, 39, 280958, 38, 280959, 38, 281176, 47, 281178, 47, 281208, 40,
+ 281210, 40, 282985, 44, 282989, 44, 283001, 39, 283005, 39, 283208, 30,
+ 283209, 27, 283224, 30, 283241, 27, 283256, 22, 283257, 22, 297334, 41,
+ 297335, 41, 297342, 38, 297343, 38, 297554, 29, 297558, 24, 297562, 29,
+ 297590, 24, 297594, 21, 297598, 21, 299365, 26, 299367, 23, 299373, 26,
+ 299383, 23, 299389, 20, 299391, 20, 299584, 31, 299585, 28, 299586, 31,
+ 299589, 28, 299590, 25, 299591, 25, 299592, 30, 299593, 27, 299602, 29,
+ 299606, 24, 299608, 30, 299610, 29, 299621, 26, 299623, 23, 299625, 27,
+ 299629, 26, 299638, 24, 299639, 23, 299640, 22, 299641, 22, 299642, 21,
+ 299645, 20, 299646, 21, 299647, 20, 299648, 61, 299649, 60, 299650, 61,
+ 299653, 60, 299654, 59, 299655, 59, 299656, 58, 299657, 57, 299666, 55,
+ 299670, 54, 299672, 58, 299674, 55, 299685, 52, 299687, 51, 299689, 57,
+ 299693, 52, 299702, 54, 299703, 51, 299704, 56, 299705, 56, 299706, 53,
+ 299709, 50, 299710, 53, 299711, 50, 299904, 61, 299906, 61, 299912, 58,
+ 299922, 55, 299928, 58, 299930, 55, 301697, 60, 301701, 60, 301705, 57,
+ 301733, 52, 301737, 57, 301741, 52, 301952, 79, 301953, 79, 301960, 76,
+ 301961, 76, 316038, 59, 316039, 59, 316054, 54, 316071, 51, 316086, 54,
+ 316087, 51, 316290, 78, 316294, 78, 316306, 73, 316310, 73, 318085, 77,
+ 318087, 77, 318117, 70, 318119, 70, 318336, 79, 318337, 79, 318338, 78,
+ 318341, 77, 318342, 78, 318343, 77, 430776, 56, 430777, 56, 430778, 53,
+ 430781, 50, 430782, 53, 430783, 50, 431000, 75, 431002, 72, 431032, 75,
+ 431034, 72, 432809, 74, 432813, 69, 432825, 74, 432829, 69, 433032, 76,
+ 433033, 76, 433048, 75, 433065, 74, 433080, 75, 433081, 74, 447158, 71,
+ 447159, 68, 447166, 71, 447167, 68, 447378, 73, 447382, 73, 447386, 72,
+ 447414, 71, 447418, 72, 447422, 71, 449189, 70, 449191, 70, 449197, 69,
+ 449207, 68, 449213, 69, 449215, 68, 449408, 67, 449409, 67, 449410, 66,
+ 449413, 64, 449414, 66, 449415, 64, 449416, 67, 449417, 67, 449426, 66,
+ 449430, 66, 449432, 65, 449434, 65, 449445, 64, 449447, 64, 449449, 63,
+ 449453, 63, 449462, 62, 449463, 62, 449464, 65, 449465, 63, 449466, 65,
+ 449469, 63, 449470, 62, 449471, 62, 449472, 19, 449473, 19, 449474, 18,
+ 449477, 16, 449478, 18, 449479, 16, 449480, 19, 449481, 19, 449490, 18,
+ 449494, 18, 449496, 17, 449498, 17, 449509, 16, 449511, 16, 449513, 15,
+ 449517, 15, 449526, 14, 449527, 14, 449528, 17, 449529, 15, 449530, 17,
+ 449533, 15, 449534, 14, 449535, 14, 449728, 19, 449729, 19, 449730, 18,
+ 449734, 18, 449736, 19, 449737, 19, 449746, 18, 449750, 18, 449752, 17,
+ 449754, 17, 449784, 17, 449786, 17, 451520, 19, 451521, 19, 451525, 16,
+ 451527, 16, 451528, 19, 451529, 19, 451557, 16, 451559, 16, 451561, 15,
+ 451565, 15, 451577, 15, 451581, 15, 451776, 19, 451777, 19, 451784, 19,
+ 451785, 19, 465858, 18, 465861, 16, 465862, 18, 465863, 16, 465874, 18,
+ 465878, 18, 465893, 16, 465895, 16, 465910, 14, 465911, 14, 465918, 14,
+ 465919, 14, 466114, 18, 466118, 18, 466130, 18, 466134, 18, 467909, 16,
+ 467911, 16, 467941, 16, 467943, 16, 468160, 13, 468161, 13, 468162, 13,
+ 468163, 13, 468164, 13, 468165, 13, 468166, 13, 468167, 13, 580568, 17,
+ 580570, 17, 580585, 15, 580589, 15, 580598, 14, 580599, 14, 580600, 17,
+ 580601, 15, 580602, 17, 580605, 15, 580606, 14, 580607, 14, 580824, 17,
+ 580826, 17, 580856, 17, 580858, 17, 582633, 15, 582637, 15, 582649, 15,
+ 582653, 15, 582856, 12, 582857, 12, 582872, 12, 582873, 12, 582888, 12,
+ 582889, 12, 582904, 12, 582905, 12, 596982, 14, 596983, 14, 596990, 14,
+ 596991, 14, 597202, 11, 597206, 11, 597210, 11, 597214, 11, 597234, 11,
+ 597238, 11, 597242, 11, 597246, 11, 599013, 10, 599015, 10, 599021, 10,
+ 599023, 10, 599029, 10, 599031, 10, 599037, 10, 599039, 10, 599232, 13,
+ 599233, 13, 599234, 13, 599235, 13, 599236, 13, 599237, 13, 599238, 13,
+ 599239, 13, 599240, 12, 599241, 12, 599250, 11, 599254, 11, 599256, 12,
+ 599257, 12, 599258, 11, 599262, 11, 599269, 10, 599271, 10, 599272, 12,
+ 599273, 12, 599277, 10, 599279, 10, 599282, 11, 599285, 10, 599286, 11,
+ 599287, 10, 599288, 12, 599289, 12, 599290, 11, 599293, 10, 599294, 11,
+ 599295, 10,
+ ],
+ p2D: [
+ 0, 0, 1, -1, 0, 0, -1, 1, 0, 2, 1, 1, 1, 2, 2, 0, 1, 2, 0, 2, 1, 0, 0, 0,
+ ],
+ p3D: [
+ 0, 0, 1, -1, 0, 0, 1, 0, -1, 0, 0, -1, 1, 0, 0, 0, 1, -1, 0, 0, -1, 0, 1,
+ 0, 0, -1, 1, 0, 2, 1, 1, 0, 1, 1, 1, -1, 0, 2, 1, 0, 1, 1, 1, -1, 1, 0, 2,
+ 0, 1, 1, 1, -1, 1, 1, 1, 3, 2, 1, 0, 3, 1, 2, 0, 1, 3, 2, 0, 1, 3, 1, 0,
+ 2, 1, 3, 0, 2, 1, 3, 0, 1, 2, 1, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 0, 2,
+ 0, 2, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 0, 0, 0, 1, 1, -1, 1, 2, 0, 0,
+ 0, 0, 1, -1, 1, 1, 2, 0, 0, 0, 0, 1, 1, 1, -1, 2, 3, 1, 1, 1, 2, 0, 0, 2,
+ 2, 3, 1, 1, 1, 2, 2, 0, 0, 2, 3, 1, 1, 1, 2, 0, 2, 0, 2, 1, 1, -1, 1, 2,
+ 0, 0, 2, 2, 1, 1, -1, 1, 2, 2, 0, 0, 2, 1, -1, 1, 1, 2, 0, 0, 2, 2, 1, -1,
+ 1, 1, 2, 0, 2, 0, 2, 1, 1, 1, -1, 2, 2, 0, 0, 2, 1, 1, 1, -1, 2, 0, 2, 0,
+ ],
+ p4D: [
+ 0, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 1, 0, 0, 0,
+ 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, 0, -1, 0, 1, 0, 0, 0, -1, 1, 0, 0, 0, 0,
+ 1, -1, 0, 0, -1, 0, 0, 1, 0, 0, -1, 0, 1, 0, 0, 0, -1, 1, 0, 2, 1, 1, 0,
+ 0, 1, 1, 1, -1, 0, 1, 1, 1, 0, -1, 0, 2, 1, 0, 1, 0, 1, 1, -1, 1, 0, 1, 1,
+ 0, 1, -1, 0, 2, 0, 1, 1, 0, 1, -1, 1, 1, 0, 1, 0, 1, 1, -1, 0, 2, 1, 0, 0,
+ 1, 1, 1, -1, 0, 1, 1, 1, 0, -1, 1, 0, 2, 0, 1, 0, 1, 1, -1, 1, 0, 1, 1, 0,
+ 1, -1, 1, 0, 2, 0, 0, 1, 1, 1, -1, 0, 1, 1, 1, 0, -1, 1, 1, 1, 4, 2, 1, 1,
+ 0, 4, 1, 2, 1, 0, 4, 1, 1, 2, 0, 1, 4, 2, 1, 0, 1, 4, 1, 2, 0, 1, 4, 1, 1,
+ 0, 2, 1, 4, 2, 0, 1, 1, 4, 1, 0, 2, 1, 4, 1, 0, 1, 2, 1, 4, 0, 2, 1, 1, 4,
+ 0, 1, 2, 1, 4, 0, 1, 1, 2, 1, 2, 1, 1, 0, 0, 3, 2, 1, 0, 0, 3, 1, 2, 0, 0,
+ 1, 2, 1, 0, 1, 0, 3, 2, 0, 1, 0, 3, 1, 0, 2, 0, 1, 2, 0, 1, 1, 0, 3, 0, 2,
+ 1, 0, 3, 0, 1, 2, 0, 1, 2, 1, 0, 0, 1, 3, 2, 0, 0, 1, 3, 1, 0, 0, 2, 1, 2,
+ 0, 1, 0, 1, 3, 0, 2, 0, 1, 3, 0, 1, 0, 2, 1, 2, 0, 0, 1, 1, 3, 0, 0, 2, 1,
+ 3, 0, 0, 1, 2, 2, 3, 1, 1, 1, 0, 2, 1, 1, 1, -1, 2, 2, 0, 0, 0, 2, 3, 1,
+ 1, 0, 1, 2, 1, 1, -1, 1, 2, 2, 0, 0, 0, 2, 3, 1, 0, 1, 1, 2, 1, -1, 1, 1,
+ 2, 2, 0, 0, 0, 2, 3, 1, 1, 1, 0, 2, 1, 1, 1, -1, 2, 0, 2, 0, 0, 2, 3, 1,
+ 1, 0, 1, 2, 1, 1, -1, 1, 2, 0, 2, 0, 0, 2, 3, 0, 1, 1, 1, 2, -1, 1, 1, 1,
+ 2, 0, 2, 0, 0, 2, 3, 1, 1, 1, 0, 2, 1, 1, 1, -1, 2, 0, 0, 2, 0, 2, 3, 1,
+ 0, 1, 1, 2, 1, -1, 1, 1, 2, 0, 0, 2, 0, 2, 3, 0, 1, 1, 1, 2, -1, 1, 1, 1,
+ 2, 0, 0, 2, 0, 2, 3, 1, 1, 0, 1, 2, 1, 1, -1, 1, 2, 0, 0, 0, 2, 2, 3, 1,
+ 0, 1, 1, 2, 1, -1, 1, 1, 2, 0, 0, 0, 2, 2, 3, 0, 1, 1, 1, 2, -1, 1, 1, 1,
+ 2, 0, 0, 0, 2, 2, 1, 1, 1, -1, 0, 1, 1, 1, 0, -1, 0, 0, 0, 0, 0, 2, 1, 1,
+ -1, 1, 0, 1, 1, 0, 1, -1, 0, 0, 0, 0, 0, 2, 1, -1, 1, 1, 0, 1, 0, 1, 1,
+ -1, 0, 0, 0, 0, 0, 2, 1, 1, -1, 0, 1, 1, 1, 0, -1, 1, 0, 0, 0, 0, 0, 2, 1,
+ -1, 1, 0, 1, 1, 0, 1, -1, 1, 0, 0, 0, 0, 0, 2, 1, -1, 0, 1, 1, 1, 0, -1,
+ 1, 1, 0, 0, 0, 0, 0, 2, 1, 1, 1, -1, 0, 1, 1, 1, 0, -1, 2, 2, 0, 0, 0, 2,
+ 1, 1, -1, 1, 0, 1, 1, 0, 1, -1, 2, 2, 0, 0, 0, 2, 1, 1, -1, 0, 1, 1, 1, 0,
+ -1, 1, 2, 2, 0, 0, 0, 2, 1, 1, 1, -1, 0, 1, 1, 1, 0, -1, 2, 0, 2, 0, 0, 2,
+ 1, -1, 1, 1, 0, 1, 0, 1, 1, -1, 2, 0, 2, 0, 0, 2, 1, -1, 1, 0, 1, 1, 0, 1,
+ -1, 1, 2, 0, 2, 0, 0, 2, 1, 1, -1, 1, 0, 1, 1, 0, 1, -1, 2, 0, 0, 2, 0, 2,
+ 1, -1, 1, 1, 0, 1, 0, 1, 1, -1, 2, 0, 0, 2, 0, 2, 1, -1, 0, 1, 1, 1, 0,
+ -1, 1, 1, 2, 0, 0, 2, 0, 2, 1, 1, -1, 0, 1, 1, 1, 0, -1, 1, 2, 0, 0, 0, 2,
+ 2, 1, -1, 1, 0, 1, 1, 0, 1, -1, 1, 2, 0, 0, 0, 2, 2, 1, -1, 0, 1, 1, 1, 0,
+ -1, 1, 1, 2, 0, 0, 0, 2, 3, 1, 1, 0, 0, 0, 2, 2, 0, 0, 0, 2, 1, 1, 1, -1,
+ 3, 1, 0, 1, 0, 0, 2, 0, 2, 0, 0, 2, 1, 1, 1, -1, 3, 1, 0, 0, 1, 0, 2, 0,
+ 0, 2, 0, 2, 1, 1, 1, -1, 3, 1, 1, 0, 0, 0, 2, 2, 0, 0, 0, 2, 1, 1, -1, 1,
+ 3, 1, 0, 1, 0, 0, 2, 0, 2, 0, 0, 2, 1, 1, -1, 1, 3, 1, 0, 0, 0, 1, 2, 0,
+ 0, 0, 2, 2, 1, 1, -1, 1, 3, 1, 1, 0, 0, 0, 2, 2, 0, 0, 0, 2, 1, -1, 1, 1,
+ 3, 1, 0, 0, 1, 0, 2, 0, 0, 2, 0, 2, 1, -1, 1, 1, 3, 1, 0, 0, 0, 1, 2, 0,
+ 0, 0, 2, 2, 1, -1, 1, 1, 3, 1, 0, 1, 0, 0, 2, 0, 2, 0, 0, 2, -1, 1, 1, 1,
+ 3, 1, 0, 0, 1, 0, 2, 0, 0, 2, 0, 2, -1, 1, 1, 1, 3, 1, 0, 0, 0, 1, 2, 0,
+ 0, 0, 2, 2, -1, 1, 1, 1, 3, 3, 2, 1, 0, 0, 3, 1, 2, 0, 0, 4, 1, 1, 1, 1,
+ 3, 3, 2, 0, 1, 0, 3, 1, 0, 2, 0, 4, 1, 1, 1, 1, 3, 3, 0, 2, 1, 0, 3, 0, 1,
+ 2, 0, 4, 1, 1, 1, 1, 3, 3, 2, 0, 0, 1, 3, 1, 0, 0, 2, 4, 1, 1, 1, 1, 3, 3,
+ 0, 2, 0, 1, 3, 0, 1, 0, 2, 4, 1, 1, 1, 1, 3, 3, 0, 0, 2, 1, 3, 0, 0, 1, 2,
+ 4, 1, 1, 1, 1, 3, 3, 2, 1, 0, 0, 3, 1, 2, 0, 0, 2, 1, 1, 1, -1, 3, 3, 2,
+ 0, 1, 0, 3, 1, 0, 2, 0, 2, 1, 1, 1, -1, 3, 3, 0, 2, 1, 0, 3, 0, 1, 2, 0,
+ 2, 1, 1, 1, -1, 3, 3, 2, 1, 0, 0, 3, 1, 2, 0, 0, 2, 1, 1, -1, 1, 3, 3, 2,
+ 0, 0, 1, 3, 1, 0, 0, 2, 2, 1, 1, -1, 1, 3, 3, 0, 2, 0, 1, 3, 0, 1, 0, 2,
+ 2, 1, 1, -1, 1, 3, 3, 2, 0, 1, 0, 3, 1, 0, 2, 0, 2, 1, -1, 1, 1, 3, 3, 2,
+ 0, 0, 1, 3, 1, 0, 0, 2, 2, 1, -1, 1, 1, 3, 3, 0, 0, 2, 1, 3, 0, 0, 1, 2,
+ 2, 1, -1, 1, 1, 3, 3, 0, 2, 1, 0, 3, 0, 1, 2, 0, 2, -1, 1, 1, 1, 3, 3, 0,
+ 2, 0, 1, 3, 0, 1, 0, 2, 2, -1, 1, 1, 1, 3, 3, 0, 0, 2, 1, 3, 0, 0, 1, 2,
+ 2, -1, 1, 1, 1,
+ ],
+ };
+
+ var Contribution2 = /** @class */ (function () {
+ function Contribution2(multiplier, xsb, ysb) {
+ this.dx = -xsb - multiplier * constants_1.SQUISH_2D;
+ this.dy = -ysb - multiplier * constants_1.SQUISH_2D;
+ this.xsb = xsb;
+ this.ysb = ysb;
+ }
+ return Contribution2;
+ })();
+ var Contribution3 = /** @class */ (function () {
+ function Contribution3(multiplier, xsb, ysb, zsb) {
+ this.dx = -xsb - multiplier * constants_1.SQUISH_3D;
+ this.dy = -ysb - multiplier * constants_1.SQUISH_3D;
+ this.dz = -zsb - multiplier * constants_1.SQUISH_3D;
+ this.xsb = xsb;
+ this.ysb = ysb;
+ this.zsb = zsb;
+ }
+ return Contribution3;
+ })();
+ var Contribution4 = /** @class */ (function () {
+ function Contribution4(multiplier, xsb, ysb, zsb, wsb) {
+ this.dx = -xsb - multiplier * constants_1.SQUISH_4D;
+ this.dy = -ysb - multiplier * constants_1.SQUISH_4D;
+ this.dz = -zsb - multiplier * constants_1.SQUISH_4D;
+ this.dw = -wsb - multiplier * constants_1.SQUISH_4D;
+ this.xsb = xsb;
+ this.ysb = ysb;
+ this.zsb = zsb;
+ this.wsb = wsb;
+ }
+ return Contribution4;
+ })();
+ function shuffleSeed(seed) {
+ var newSeed = new Uint32Array(1);
+ newSeed[0] = seed[0] * 1664525 + 1013904223;
+ return newSeed;
+ }
+ OpenSimplexNoise = /** @class */ (function () {
+ function OpenSimplexNoise(clientSeed) {
+ this.initialize();
+ this.perm = new Uint8Array(256);
+ this.perm2D = new Uint8Array(256);
+ this.perm3D = new Uint8Array(256);
+ this.perm4D = new Uint8Array(256);
+ var source = new Uint8Array(256);
+ for (var i = 0; i < 256; i++) source[i] = i;
+ var seed = new Uint32Array(1);
+ seed[0] = clientSeed;
+ seed = shuffleSeed(shuffleSeed(shuffleSeed(seed)));
+ for (var i = 255; i >= 0; i--) {
+ seed = shuffleSeed(seed);
+ var r = new Uint32Array(1);
+ r[0] = (seed[0] + 31) % (i + 1);
+ if (r[0] < 0) r[0] += i + 1;
+ this.perm[i] = source[r[0]];
+ this.perm2D[i] = this.perm[i] & 0x0e;
+ this.perm3D[i] = (this.perm[i] % 24) * 3;
+ this.perm4D[i] = this.perm[i] & 0xfc;
+ source[r[0]] = source[i];
+ }
+ }
+ OpenSimplexNoise.prototype.array2D = function (width, height) {
+ var output = new Array(width);
+ for (var x = 0; x < width; x++) {
+ output[x] = new Array(height);
+ for (var y = 0; y < height; y++) {
+ output[x][y] = this.noise2D(x, y);
+ }
+ }
+ return output;
+ };
+ OpenSimplexNoise.prototype.array3D = function (width, height, depth) {
+ var output = new Array(width);
+ for (var x = 0; x < width; x++) {
+ output[x] = new Array(height);
+ for (var y = 0; y < height; y++) {
+ output[x][y] = new Array(depth);
+ for (var z = 0; z < depth; z++) {
+ output[x][y][z] = this.noise3D(x, y, z);
+ }
+ }
+ }
+ return output;
+ };
+ OpenSimplexNoise.prototype.array4D = function (
+ width,
+ height,
+ depth,
+ wLength
+ ) {
+ var output = new Array(width);
+ for (var x = 0; x < width; x++) {
+ output[x] = new Array(height);
+ for (var y = 0; y < height; y++) {
+ output[x][y] = new Array(depth);
+ for (var z = 0; z < depth; z++) {
+ output[x][y][z] = new Array(wLength);
+ for (var w = 0; w < wLength; w++) {
+ output[x][y][z][w] = this.noise4D(x, y, z, w);
+ }
+ }
+ }
+ }
+ return output;
+ };
+ OpenSimplexNoise.prototype.noise2D = function (x, y) {
+ var stretchOffset = (x + y) * constants_1.STRETCH_2D;
+ var xs = x + stretchOffset;
+ var ys = y + stretchOffset;
+ var xsb = Math.floor(xs);
+ var ysb = Math.floor(ys);
+ var squishOffset = (xsb + ysb) * constants_1.SQUISH_2D;
+ var dx0 = x - (xsb + squishOffset);
+ var dy0 = y - (ysb + squishOffset);
+ var xins = xs - xsb;
+ var yins = ys - ysb;
+ var inSum = xins + yins;
+ var hash =
+ (xins - yins + 1) |
+ (inSum << 1) |
+ ((inSum + yins) << 2) |
+ ((inSum + xins) << 4);
+ var value = 0;
+ for (var c = this.lookup2D[hash]; c !== undefined; c = c.next) {
+ var dx = dx0 + c.dx;
+ var dy = dy0 + c.dy;
+ var attn = 2 - dx * dx - dy * dy;
+ if (attn > 0) {
+ var px = xsb + c.xsb;
+ var py = ysb + c.ysb;
+ var indexPartA = this.perm[px & 0xff];
+ var index = this.perm2D[(indexPartA + py) & 0xff];
+ var valuePart =
+ constants_1.gradients2D[index] * dx +
+ constants_1.gradients2D[index + 1] * dy;
+ value += attn * attn * attn * attn * valuePart;
+ }
+ }
+ return value * constants_1.NORM_2D;
+ };
+ OpenSimplexNoise.prototype.noise3D = function (x, y, z) {
+ var stretchOffset = (x + y + z) * constants_1.STRETCH_3D;
+ var xs = x + stretchOffset;
+ var ys = y + stretchOffset;
+ var zs = z + stretchOffset;
+ var xsb = Math.floor(xs);
+ var ysb = Math.floor(ys);
+ var zsb = Math.floor(zs);
+ var squishOffset = (xsb + ysb + zsb) * constants_1.SQUISH_3D;
+ var dx0 = x - (xsb + squishOffset);
+ var dy0 = y - (ysb + squishOffset);
+ var dz0 = z - (zsb + squishOffset);
+ var xins = xs - xsb;
+ var yins = ys - ysb;
+ var zins = zs - zsb;
+ var inSum = xins + yins + zins;
+ var hash =
+ (yins - zins + 1) |
+ ((xins - yins + 1) << 1) |
+ ((xins - zins + 1) << 2) |
+ (inSum << 3) |
+ ((inSum + zins) << 5) |
+ ((inSum + yins) << 7) |
+ ((inSum + xins) << 9);
+ var value = 0;
+ for (var c = this.lookup3D[hash]; c !== undefined; c = c.next) {
+ var dx = dx0 + c.dx;
+ var dy = dy0 + c.dy;
+ var dz = dz0 + c.dz;
+ var attn = 2 - dx * dx - dy * dy - dz * dz;
+ if (attn > 0) {
+ var px = xsb + c.xsb;
+ var py = ysb + c.ysb;
+ var pz = zsb + c.zsb;
+ var indexPartA = this.perm[px & 0xff];
+ var indexPartB = this.perm[(indexPartA + py) & 0xff];
+ var index = this.perm3D[(indexPartB + pz) & 0xff];
+ var valuePart =
+ constants_1.gradients3D[index] * dx +
+ constants_1.gradients3D[index + 1] * dy +
+ constants_1.gradients3D[index + 2] * dz;
+ value += attn * attn * attn * attn * valuePart;
+ }
+ }
+ return value * constants_1.NORM_3D;
+ };
+ OpenSimplexNoise.prototype.noise4D = function (x, y, z, w) {
+ var stretchOffset = (x + y + z + w) * constants_1.STRETCH_4D;
+ var xs = x + stretchOffset;
+ var ys = y + stretchOffset;
+ var zs = z + stretchOffset;
+ var ws = w + stretchOffset;
+ var xsb = Math.floor(xs);
+ var ysb = Math.floor(ys);
+ var zsb = Math.floor(zs);
+ var wsb = Math.floor(ws);
+ var squishOffset = (xsb + ysb + zsb + wsb) * constants_1.SQUISH_4D;
+ var dx0 = x - (xsb + squishOffset);
+ var dy0 = y - (ysb + squishOffset);
+ var dz0 = z - (zsb + squishOffset);
+ var dw0 = w - (wsb + squishOffset);
+ var xins = xs - xsb;
+ var yins = ys - ysb;
+ var zins = zs - zsb;
+ var wins = ws - wsb;
+ var inSum = xins + yins + zins + wins;
+ var hash =
+ (zins - wins + 1) |
+ ((yins - zins + 1) << 1) |
+ ((yins - wins + 1) << 2) |
+ ((xins - yins + 1) << 3) |
+ ((xins - zins + 1) << 4) |
+ ((xins - wins + 1) << 5) |
+ (inSum << 6) |
+ ((inSum + wins) << 8) |
+ ((inSum + zins) << 11) |
+ ((inSum + yins) << 14) |
+ ((inSum + xins) << 17);
+ var value = 0;
+ for (var c = this.lookup4D[hash]; c !== undefined; c = c.next) {
+ var dx = dx0 + c.dx;
+ var dy = dy0 + c.dy;
+ var dz = dz0 + c.dz;
+ var dw = dw0 + c.dw;
+ var attn = 2 - dx * dx - dy * dy - dz * dz - dw * dw;
+ if (attn > 0) {
+ var px = xsb + c.xsb;
+ var py = ysb + c.ysb;
+ var pz = zsb + c.zsb;
+ var pw = wsb + c.wsb;
+ var indexPartA = this.perm[px & 0xff];
+ var indexPartB = this.perm[(indexPartA + py) & 0xff];
+ var indexPartC = this.perm[(indexPartB + pz) & 0xff];
+ var index = this.perm4D[(indexPartC + pw) & 0xff];
+ var valuePart =
+ constants_1.gradients4D[index] * dx +
+ constants_1.gradients4D[index + 1] * dy +
+ constants_1.gradients4D[index + 2] * dz +
+ constants_1.gradients4D[index + 3] * dw;
+ value += attn * attn * attn * attn * valuePart;
+ }
+ }
+ return value * constants_1.NORM_4D;
+ };
+ OpenSimplexNoise.prototype.initialize = function () {
+ var contributions2D = [];
+ for (var i = 0; i < constants_1.p2D.length; i += 4) {
+ var baseSet = constants_1.base2D[constants_1.p2D[i]];
+ var previous = null;
+ var current = null;
+ for (var k = 0; k < baseSet.length; k += 3) {
+ current = new Contribution2(
+ baseSet[k],
+ baseSet[k + 1],
+ baseSet[k + 2]
+ );
+ if (previous === null) contributions2D[i / 4] = current;
+ else previous.next = current;
+ previous = current;
+ }
+ current.next = new Contribution2(
+ constants_1.p2D[i + 1],
+ constants_1.p2D[i + 2],
+ constants_1.p2D[i + 3]
+ );
+ }
+ this.lookup2D = [];
+ for (var i = 0; i < constants_1.lookupPairs2D.length; i += 2) {
+ this.lookup2D[constants_1.lookupPairs2D[i]] =
+ contributions2D[constants_1.lookupPairs2D[i + 1]];
+ }
+ var contributions3D = [];
+ for (var i = 0; i < constants_1.p3D.length; i += 9) {
+ var baseSet = constants_1.base3D[constants_1.p3D[i]];
+ var previous = null;
+ var current = null;
+ for (var k = 0; k < baseSet.length; k += 4) {
+ current = new Contribution3(
+ baseSet[k],
+ baseSet[k + 1],
+ baseSet[k + 2],
+ baseSet[k + 3]
+ );
+ if (previous === null) contributions3D[i / 9] = current;
+ else previous.next = current;
+ previous = current;
+ }
+ current.next = new Contribution3(
+ constants_1.p3D[i + 1],
+ constants_1.p3D[i + 2],
+ constants_1.p3D[i + 3],
+ constants_1.p3D[i + 4]
+ );
+ current.next.next = new Contribution3(
+ constants_1.p3D[i + 5],
+ constants_1.p3D[i + 6],
+ constants_1.p3D[i + 7],
+ constants_1.p3D[i + 8]
+ );
+ }
+ this.lookup3D = [];
+ for (var i = 0; i < constants_1.lookupPairs3D.length; i += 2) {
+ this.lookup3D[constants_1.lookupPairs3D[i]] =
+ contributions3D[constants_1.lookupPairs3D[i + 1]];
+ }
+ var contributions4D = [];
+ for (var i = 0; i < constants_1.p4D.length; i += 16) {
+ var baseSet = constants_1.base4D[constants_1.p4D[i]];
+ var previous = null;
+ var current = null;
+ for (var k = 0; k < baseSet.length; k += 5) {
+ current = new Contribution4(
+ baseSet[k],
+ baseSet[k + 1],
+ baseSet[k + 2],
+ baseSet[k + 3],
+ baseSet[k + 4]
+ );
+ if (previous === null) contributions4D[i / 16] = current;
+ else previous.next = current;
+ previous = current;
+ }
+ current.next = new Contribution4(
+ constants_1.p4D[i + 1],
+ constants_1.p4D[i + 2],
+ constants_1.p4D[i + 3],
+ constants_1.p4D[i + 4],
+ constants_1.p4D[i + 5]
+ );
+ current.next.next = new Contribution4(
+ constants_1.p4D[i + 6],
+ constants_1.p4D[i + 7],
+ constants_1.p4D[i + 8],
+ constants_1.p4D[i + 9],
+ constants_1.p4D[i + 10]
+ );
+ current.next.next.next = new Contribution4(
+ constants_1.p4D[i + 11],
+ constants_1.p4D[i + 12],
+ constants_1.p4D[i + 13],
+ constants_1.p4D[i + 14],
+ constants_1.p4D[i + 15]
+ );
+ }
+ this.lookup4D = [];
+ for (var i = 0; i < constants_1.lookupPairs4D.length; i += 2) {
+ this.lookup4D[constants_1.lookupPairs4D[i]] =
+ contributions4D[constants_1.lookupPairs4D[i + 1]];
+ }
+ };
+ return OpenSimplexNoise;
+ })();
+})();
diff --git a/hackx/sections.js b/hackx/sections.js
new file mode 100644
index 00000000..ac3b1bbd
--- /dev/null
+++ b/hackx/sections.js
@@ -0,0 +1,2344 @@
+// sections.js — Canvas animations and interactivity for Hack X sections
+(function () {
+ "use strict";
+
+ const RED = "#4fd1d9";
+ const DARK = "#0a1628";
+ const RED_RGB = [79, 209, 217];
+ const CRT_CURVATURE = 4.5; // lower = curvier
+ const CURSOR_BG = DARK;
+ const CURSOR_FG = RED;
+ const CURSOR_STROKE_PX = 3;
+ const CURSOR_SCALE = 1.2;
+ const CURSOR_ROT = -Math.PI / 5;
+ const CURSOR_OFFSET = 10;
+
+ function shouldUseCrtCurvature() {
+ // Reuse the project's canonical detector from `utils.js` when available.
+ if (typeof window.isTouchScreenDevice === "function") {
+ return !window.isTouchScreenDevice();
+ }
+
+ // Fallback: avoid disabling on desktops that expose touch APIs.
+ const coarsePointer =
+ window.matchMedia && window.matchMedia("(pointer:coarse)").matches;
+ return !coarsePointer;
+ }
+
+ function shouldUseCustomCursor() {
+ // Skip on touch/coarse pointer devices.
+ if (typeof window.isTouchScreenDevice === "function") {
+ return !window.isTouchScreenDevice();
+ }
+ const coarsePointer =
+ window.matchMedia && window.matchMedia("(pointer:coarse)").matches;
+ return !coarsePointer;
+ }
+
+ function initGlobalCustomCursor() {
+ if (!shouldUseCustomCursor()) return;
+
+ const cursorCanvas = document.createElement("canvas");
+ cursorCanvas.id = "global-custom-cursor";
+ cursorCanvas.style.cssText = `
+ position: fixed;
+ top: 0; left: 0;
+ width: 100vw; height: 100vh;
+ z-index: 9998;
+ pointer-events: none;
+ `;
+ document.body.appendChild(cursorCanvas);
+
+ const ctx = cursorCanvas.getContext("2d");
+ if (!ctx) {
+ cursorCanvas.remove();
+ return;
+ }
+
+ function resize() {
+ const dpr = window.devicePixelRatio || 1;
+ cursorCanvas.width = Math.max(1, Math.floor(window.innerWidth * dpr));
+ cursorCanvas.height = Math.max(1, Math.floor(window.innerHeight * dpr));
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
+ }
+ resize();
+ window.addEventListener("resize", resize);
+
+ let mouseX = -9999;
+ let mouseY = -9999;
+ let hide = false;
+
+ function isInsideHero(x, y) {
+ const hero = document.getElementById("hero-section");
+ if (!hero) return false;
+ const r = hero.getBoundingClientRect();
+ return x >= r.left && x <= r.right && y >= r.top && y <= r.bottom;
+ }
+
+ window.addEventListener(
+ "mousemove",
+ (e) => {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+ hide = isInsideHero(mouseX, mouseY);
+ },
+ { passive: true },
+ );
+
+ window.addEventListener(
+ "mouseleave",
+ () => {
+ mouseX = -9999;
+ mouseY = -9999;
+ },
+ { passive: true },
+ );
+
+ function draw() {
+ ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
+ if (!hide && mouseX >= 0 && mouseY >= 0) {
+ ctx.save();
+ ctx.translate(mouseX + CURSOR_OFFSET, mouseY + CURSOR_OFFSET);
+ ctx.scale(CURSOR_SCALE, CURSOR_SCALE);
+ ctx.rotate(CURSOR_ROT);
+
+ ctx.fillStyle = CURSOR_BG;
+ ctx.strokeStyle = CURSOR_FG;
+ ctx.lineWidth = CURSOR_STROKE_PX;
+ ctx.beginPath();
+ ctx.moveTo(0, -10);
+ ctx.lineTo(7.5, 10);
+ ctx.lineTo(0, 5);
+ ctx.lineTo(-7.5, 10);
+ ctx.closePath();
+ ctx.fill();
+ ctx.stroke();
+ ctx.restore();
+ }
+ requestAnimationFrame(draw);
+ }
+ requestAnimationFrame(draw);
+ }
+
+ function initGlobalCrtCurvatureForSectionCanvases() {
+ if (!shouldUseCrtCurvature()) return;
+
+ // Signal to the p5 layer that global CRT is active (so it can skip its own CRT pass).
+ window.__HACKX_GLOBAL_CRT__ = true;
+
+ let sourceCanvases = [];
+ function collectSourceCanvases() {
+ // Include the p5 hero canvas too so the curvature feels like one continuous screen.
+ const all = Array.from(
+ document.querySelectorAll(".section canvas, #footer-section canvas"),
+ ).filter((c) => !(c instanceof HTMLCanvasElement ? c.classList.contains("crt-global-canvas") : false));
+ sourceCanvases = all;
+ sourceCanvases.forEach((c) => {
+ // Hide all source canvases; the global CRT canvas will draw them instead.
+ if (!c.classList.contains("crt-global-canvas")) c.style.opacity = "0";
+ });
+ }
+
+ collectSourceCanvases();
+
+ const glCanvas = document.createElement("canvas");
+ glCanvas.className = "crt-global-canvas";
+ glCanvas.style.cssText = `
+ position: fixed;
+ top: 0; left: 0;
+ width: 100vw; height: 100vh;
+ z-index: 0;
+ pointer-events: none;
+ `;
+ document.body.appendChild(glCanvas);
+
+ const gl =
+ glCanvas.getContext("webgl", {
+ alpha: true,
+ antialias: false,
+ premultipliedAlpha: true,
+ preserveDrawingBuffer: false,
+ }) || glCanvas.getContext("experimental-webgl");
+ if (!gl) {
+ glCanvas.remove();
+ return;
+ }
+
+ // If canvases are created after DOMContentLoaded (p5 does this), observe and collect.
+ const observer = new MutationObserver(() => collectSourceCanvases());
+ observer.observe(document.body, { childList: true, subtree: true });
+
+ const composeCanvas = document.createElement("canvas");
+ const composeCtx = composeCanvas.getContext("2d", { alpha: true });
+ // Keep UI (game text/boxes) crisp when compositing/scaling.
+ composeCtx.imageSmoothingEnabled = false;
+
+ const vertSrc = `
+ attribute vec2 a_pos;
+ varying vec2 v_uv;
+ void main() {
+ v_uv = (a_pos + 1.0) * 0.5;
+ gl_Position = vec4(a_pos, 0.0, 1.0);
+ }
+ `;
+
+ const fragSrc = `
+ precision mediump float;
+ varying vec2 v_uv;
+ uniform sampler2D u_tex;
+ uniform vec2 u_curvature;
+
+ vec2 curveRemapUV(vec2 uv) {
+ uv = uv * 2.0 - 1.0;
+ vec2 offset = abs(uv.yx) / u_curvature;
+ uv = uv + uv * offset * offset;
+ uv = uv * 0.5 + 0.5;
+ return uv;
+ }
+
+ void main() {
+ vec2 uv = v_uv;
+ vec2 remappedUV = curveRemapUV(uv);
+ if (remappedUV.x < 0.0 || remappedUV.y < 0.0 || remappedUV.x > 1.0 || remappedUV.y > 1.0) {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
+ return;
+ }
+ gl_FragColor = texture2D(u_tex, remappedUV);
+ }
+ `;
+
+ function compileShader(type, src) {
+ const s = gl.createShader(type);
+ gl.shaderSource(s, src);
+ gl.compileShader(s);
+ if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
+ gl.deleteShader(s);
+ return null;
+ }
+ return s;
+ }
+
+ function createProgram(vsSrc, fsSrc) {
+ const vs = compileShader(gl.VERTEX_SHADER, vsSrc);
+ const fs = compileShader(gl.FRAGMENT_SHADER, fsSrc);
+ if (!vs || !fs) return null;
+ const p = gl.createProgram();
+ gl.attachShader(p, vs);
+ gl.attachShader(p, fs);
+ gl.linkProgram(p);
+ gl.deleteShader(vs);
+ gl.deleteShader(fs);
+ if (!gl.getProgramParameter(p, gl.LINK_STATUS)) {
+ gl.deleteProgram(p);
+ return null;
+ }
+ return p;
+ }
+
+ const program = createProgram(vertSrc, fragSrc);
+ if (!program) {
+ glCanvas.remove();
+ sourceCanvases.forEach((c) => (c.style.opacity = ""));
+ return;
+ }
+
+ const quad = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, quad);
+ gl.bufferData(
+ gl.ARRAY_BUFFER,
+ new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),
+ gl.STATIC_DRAW,
+ );
+
+ const aPos = gl.getAttribLocation(program, "a_pos");
+ const uTex = gl.getUniformLocation(program, "u_tex");
+ const uCurv = gl.getUniformLocation(program, "u_curvature");
+
+ const texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ // Nearest-neighbor to avoid blurring pixel-ish UI.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+
+ function resize() {
+ const dpr = window.devicePixelRatio || 1;
+ const w = Math.max(1, Math.floor(window.innerWidth * dpr));
+ const h = Math.max(1, Math.floor(window.innerHeight * dpr));
+ glCanvas.width = w;
+ glCanvas.height = h;
+ composeCanvas.width = w;
+ composeCanvas.height = h;
+ gl.viewport(0, 0, w, h);
+ }
+
+ resize();
+ window.addEventListener("resize", resize);
+
+ let lastFrame = 0;
+ const minFrameMs = 1000 / 30; // cap at ~30fps for perf
+ const FLAT_CURVATURE = 10000.0;
+
+ function draw(now) {
+ if (now - lastFrame < minFrameMs) {
+ requestAnimationFrame(draw);
+ return;
+ }
+ lastFrame = now;
+
+ // Fade curvature to flat as the footer enters the viewport.
+ // t = 0 -> full curvature, t = 1 -> flat.
+ let t = 0;
+ const footer = document.getElementById("footer-section");
+ if (footer) {
+ const r = footer.getBoundingClientRect();
+ const fadeStart = window.innerHeight * 0.65;
+ const fadeEnd = window.innerHeight * 0.15;
+ if (r.top < fadeStart) {
+ t = Math.min(1, Math.max(0, (fadeStart - r.top) / (fadeStart - fadeEnd)));
+ }
+ }
+ const curv = CRT_CURVATURE + (FLAT_CURVATURE - CRT_CURVATURE) * t;
+
+ // Composite all section canvases into one viewport-sized canvas in screen space.
+ composeCtx.clearRect(0, 0, composeCanvas.width, composeCanvas.height);
+ composeCtx.fillStyle = DARK;
+ composeCtx.fillRect(0, 0, composeCanvas.width, composeCanvas.height);
+ const dpr = window.devicePixelRatio || 1;
+ for (const c of sourceCanvases) {
+ if (!c || c === glCanvas) continue;
+ const rect = c.getBoundingClientRect();
+ if (rect.width <= 1 || rect.height <= 1) continue;
+ if (rect.bottom < 0 || rect.top > window.innerHeight) continue;
+ const dx = rect.left * dpr;
+ const dy = rect.top * dpr;
+ const dw = rect.width * dpr;
+ const dh = rect.height * dpr;
+ try {
+ composeCtx.drawImage(c, dx, dy, dw, dh);
+ } catch {
+ // Ignore transient drawImage failures (e.g., zero-sized during layout).
+ }
+ }
+
+ // Upload composed viewport to WebGL texture and curve it once.
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
+ gl.texImage2D(
+ gl.TEXTURE_2D,
+ 0,
+ gl.RGBA,
+ gl.RGBA,
+ gl.UNSIGNED_BYTE,
+ composeCanvas,
+ );
+
+ gl.useProgram(program);
+ gl.bindBuffer(gl.ARRAY_BUFFER, quad);
+ gl.enableVertexAttribArray(aPos);
+ gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.uniform1i(uTex, 0);
+ gl.uniform2f(uCurv, curv, curv);
+
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+ requestAnimationFrame(draw);
+ }
+
+ requestAnimationFrame(draw);
+ }
+
+ document.addEventListener("DOMContentLoaded", init);
+
+ function init() {
+ // Canvas backgrounds (performant, GPU-accelerated)
+ initAboutCanvas();
+ initNexusCanvas();
+ initSpectraCanvas();
+ initPrizesCanvas();
+ initFooterCanvas();
+ // Core (one-time CSS transitions, no jank)
+ initScrollFadeIn();
+ initPrizeCounters();
+ // initScrollProgressBar(); // removed — was showing blue line at top
+ initAnnouncements();
+ // Clean interactions (pure CSS, no rAF loops)
+ initHoverLineTrace();
+ initRevealOnScroll();
+ initTeamGrid();
+ initPerksBgCanvas();
+ // Easter eggs (hidden, zero perf cost until triggered)
+ initTripleClick();
+ initFooterCopyrightHover();
+ initCodecellMatrix();
+ initBottomMessage();
+ initTenFireworks();
+ initTrackTagFlash();
+ initIdleMessage();
+ initMusicDanceExperience();
+ initGlobalCrtCurvatureForSectionCanvases();
+ initGlobalCustomCursor();
+ }
+
+ // ===== LENIS SMOOTH SCROLL =====
+ function initLenis() {
+ if (typeof Lenis === "undefined") return;
+ const lenis = new Lenis({
+ duration: 2.2,
+ easing: (t) => 1 - Math.pow(1 - t, 4),
+ orientation: "vertical",
+ smoothWheel: true,
+ wheelMultiplier: 0.7,
+ touchMultiplier: 1.5,
+ });
+
+ function raf(time) {
+ lenis.raf(time);
+ requestAnimationFrame(raf);
+ }
+ requestAnimationFrame(raf);
+
+ document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
+ anchor.addEventListener("click", (e) => {
+ e.preventDefault();
+ const target = document.querySelector(anchor.getAttribute("href"));
+ if (target) lenis.scrollTo(target);
+ });
+ });
+ }
+
+ // ===== ABOUT: Binary Rain (SUBTLE — low alpha, slow fall) =====
+ function initAboutCanvas() {
+ const canvas = document.getElementById("about-canvas");
+ if (!canvas) return;
+ const ctx = canvas.getContext("2d");
+ const chars = "01アカサタナハマヤラワ{}[]<>/\\|=+-*&^%$#@!HACKXCODECEL";
+ let columns, drops;
+
+ function resize() {
+ canvas.width = canvas.parentElement.offsetWidth;
+ canvas.height = canvas.parentElement.offsetHeight;
+ columns = Math.floor(canvas.width / 14);
+ drops = new Array(columns).fill(1);
+ }
+
+ function draw() {
+ ctx.fillStyle = "rgba(10, 22, 40, 0.04)";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ ctx.fillStyle = "rgba(79, 209, 217, 0.12)";
+ ctx.font = "12px Courier New";
+
+ for (let i = 0; i < drops.length; i++) {
+ const char = chars[Math.floor(Math.random() * chars.length)];
+ ctx.fillText(char, i * 14, drops[i] * 14);
+ if (drops[i] * 14 > canvas.height && Math.random() > 0.985)
+ drops[i] = 0;
+ if (Math.random() > 0.3) drops[i]++;
+ }
+ requestAnimationFrame(draw);
+ }
+
+ resize();
+ window.addEventListener("resize", resize);
+ draw();
+ }
+
+ // ===== NEXUS: Neural Network Nodes =====
+ function initNexusCanvas() {
+ const canvas = document.getElementById("nexus-canvas");
+ if (!canvas) return;
+ const ctx = canvas.getContext("2d");
+ let nodes = [];
+ const NODE_COUNT = 25;
+
+ function resize() {
+ canvas.width = canvas.parentElement.offsetWidth;
+ canvas.height = canvas.parentElement.offsetHeight;
+ nodes = [];
+ for (let i = 0; i < NODE_COUNT; i++) {
+ nodes.push({
+ x: Math.random() * canvas.width,
+ y: Math.random() * canvas.height,
+ vx: (Math.random() - 0.5) * 0.5,
+ vy: (Math.random() - 0.5) * 0.5,
+ radius: Math.random() * 3 + 1,
+ pulse: Math.random() * Math.PI * 2,
+ });
+ }
+ }
+
+ function draw() {
+ ctx.fillStyle = "rgba(10, 22, 40, 0.15)";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ for (let i = 0; i < nodes.length; i++) {
+ for (let j = i + 1; j < nodes.length; j++) {
+ const dx = nodes[i].x - nodes[j].x;
+ const dy = nodes[i].y - nodes[j].y;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < 120) {
+ const alpha = (1 - dist / 120) * 0.3;
+ ctx.strokeStyle = `rgba(${RED_RGB.join(",")}, ${alpha})`;
+ ctx.lineWidth = 0.5;
+ ctx.beginPath();
+ ctx.moveTo(nodes[i].x, nodes[i].y);
+ ctx.lineTo(nodes[j].x, nodes[j].y);
+ ctx.stroke();
+ }
+ }
+ }
+
+ nodes.forEach((n) => {
+ n.x += n.vx;
+ n.y += n.vy;
+ n.pulse += 0.03;
+ if (n.x < 0 || n.x > canvas.width) n.vx *= -1;
+ if (n.y < 0 || n.y > canvas.height) n.vy *= -1;
+
+ const glow = Math.sin(n.pulse) * 0.3 + 0.4;
+ ctx.beginPath();
+ ctx.arc(n.x, n.y, n.radius + Math.sin(n.pulse) * 1, 0, Math.PI * 2);
+ ctx.fillStyle = `rgba(${RED_RGB.join(",")}, ${glow})`;
+ ctx.fill();
+ });
+
+ requestAnimationFrame(draw);
+ }
+
+ resize();
+ window.addEventListener("resize", resize);
+ draw();
+ }
+
+ // ===== SPECTRA: Orbiting Blockchain Nodes =====
+ function initSpectraCanvas() {
+ const canvas = document.getElementById("spectra-canvas");
+ if (!canvas) return;
+ const ctx = canvas.getContext("2d");
+ let rings = [];
+ let time = 0;
+
+ function resize() {
+ canvas.width = canvas.parentElement.offsetWidth;
+ canvas.height = canvas.parentElement.offsetHeight;
+ const cx = canvas.width / 2;
+ const cy = canvas.height / 2;
+ const maxR = Math.min(canvas.width, canvas.height) * 0.4;
+ rings = [];
+ for (let i = 0; i < 4; i++) {
+ const r = maxR * (0.3 + i * 0.2);
+ const nodeCount = 3 + i * 2;
+ const ringNodes = [];
+ for (let j = 0; j < nodeCount; j++) {
+ ringNodes.push({
+ angle: (j / nodeCount) * Math.PI * 2,
+ speed: (0.005 + i * 0.002) * (i % 2 === 0 ? 1 : -1),
+ });
+ }
+ rings.push({ radius: r, nodes: ringNodes, cx, cy });
+ }
+ }
+
+ function draw() {
+ ctx.fillStyle = "rgba(10, 22, 40, 0.1)";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ time += 0.01;
+
+ rings.forEach((ring, ri) => {
+ ctx.strokeStyle = `rgba(${RED_RGB.join(",")}, 0.08)`;
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+ ctx.arc(ring.cx, ring.cy, ring.radius, 0, Math.PI * 2);
+ ctx.stroke();
+
+ ring.nodes.forEach((n) => {
+ n.angle += n.speed;
+ const x = ring.cx + Math.cos(n.angle) * ring.radius;
+ const y = ring.cy + Math.sin(n.angle) * ring.radius;
+
+ ctx.beginPath();
+ ctx.arc(x, y, 3, 0, Math.PI * 2);
+ ctx.fillStyle = `rgba(${RED_RGB.join(",")}, 0.6)`;
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.arc(x, y, 8, 0, Math.PI * 2);
+ ctx.fillStyle = `rgba(${RED_RGB.join(",")}, 0.1)`;
+ ctx.fill();
+ });
+
+ if (ri < rings.length - 1) {
+ const nextRing = rings[ri + 1];
+ ring.nodes.forEach((n1) => {
+ const x1 = ring.cx + Math.cos(n1.angle) * ring.radius;
+ const y1 = ring.cy + Math.sin(n1.angle) * ring.radius;
+ nextRing.nodes.forEach((n2) => {
+ const x2 = nextRing.cx + Math.cos(n2.angle) * nextRing.radius;
+ const y2 = nextRing.cy + Math.sin(n2.angle) * nextRing.radius;
+ const dist = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
+ if (dist < 100) {
+ ctx.strokeStyle = `rgba(${RED_RGB.join(",")}, ${(1 - dist / 100) * 0.15})`;
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
+ }
+ });
+ });
+ }
+ });
+
+ requestAnimationFrame(draw);
+ }
+
+ resize();
+ window.addEventListener("resize", resize);
+ draw();
+ }
+
+ // ===== PRIZES: Floating ASCII =====
+ function initPrizesCanvas() {
+ const canvas = document.getElementById("prizes-canvas");
+ if (!canvas) return;
+ const ctx = canvas.getContext("2d");
+ const symbols = ["$", "★", "◆", "▲", "●", "✦", "⬡", "0", "1"];
+ let floaters = [];
+
+ function resize() {
+ canvas.width = canvas.parentElement.offsetWidth;
+ canvas.height = canvas.parentElement.offsetHeight;
+ floaters = [];
+ for (let i = 0; i < 40; i++) {
+ floaters.push({
+ x: Math.random() * canvas.width,
+ y: Math.random() * canvas.height,
+ vy: -(Math.random() * 0.3 + 0.1),
+ char: symbols[Math.floor(Math.random() * symbols.length)],
+ alpha: Math.random() * 0.15 + 0.05,
+ size: Math.random() * 14 + 8,
+ drift: (Math.random() - 0.5) * 0.3,
+ });
+ }
+ }
+
+ function draw() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ floaters.forEach((f) => {
+ f.y += f.vy;
+ f.x += f.drift;
+ if (f.y < -20) {
+ f.y = canvas.height + 20;
+ f.x = Math.random() * canvas.width;
+ }
+ if (f.x < -20) f.x = canvas.width + 20;
+ if (f.x > canvas.width + 20) f.x = -20;
+
+ ctx.font = `${f.size}px Courier New`;
+ ctx.fillStyle = `rgba(${RED_RGB.join(",")}, ${f.alpha})`;
+ ctx.fillText(f.char, f.x, f.y);
+ });
+
+ requestAnimationFrame(draw);
+ }
+
+ resize();
+ window.addEventListener("resize", resize);
+ draw();
+ }
+
+ // ===== FOOTER: Particle Field =====
+ function initFooterCanvas() {
+ const canvas = document.getElementById("footer-canvas");
+ if (!canvas) return;
+ const ctx = canvas.getContext("2d");
+ let particles = [];
+
+ function resize() {
+ canvas.width = canvas.parentElement.offsetWidth;
+ canvas.height = canvas.parentElement.offsetHeight;
+ particles = [];
+ for (let i = 0; i < 60; i++) {
+ particles.push({
+ x: Math.random() * canvas.width,
+ y: Math.random() * canvas.height,
+ vx: (Math.random() - 0.5) * 0.3,
+ vy: (Math.random() - 0.5) * 0.3,
+ size: Math.random() * 2 + 0.5,
+ alpha: Math.random() * 0.2 + 0.05,
+ });
+ }
+ }
+
+ function draw() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ particles.forEach((p) => {
+ p.x += p.vx;
+ p.y += p.vy;
+ if (p.x < 0 || p.x > canvas.width) p.vx *= -1;
+ if (p.y < 0 || p.y > canvas.height) p.vy *= -1;
+
+ ctx.beginPath();
+ ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
+ ctx.fillStyle = `rgba(${RED_RGB.join(",")}, ${p.alpha})`;
+ ctx.fill();
+ });
+
+ requestAnimationFrame(draw);
+ }
+
+ resize();
+ window.addEventListener("resize", resize);
+ draw();
+ }
+
+ // ===== SCROLL FADE-IN (smoother: 0.6s ease-out) =====
+ function initScrollFadeIn() {
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ entry.target.classList.add("visible");
+ }
+ });
+ },
+ { threshold: 0.2 },
+ );
+
+ document
+ .querySelectorAll(".timeline-item, .about-stat")
+ .forEach((item) => observer.observe(item));
+
+ document.querySelectorAll(".section-content").forEach((el) => {
+ el.style.opacity = "0";
+ el.style.transform = "translateY(20px)";
+ el.style.transition = "opacity 0.6s ease-out, transform 0.6s ease-out";
+ });
+
+ const contentObserver = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ entry.target.style.opacity = "1";
+ entry.target.style.transform = "translateY(0)";
+ }
+ });
+ },
+ { threshold: 0.1 },
+ );
+
+ document
+ .querySelectorAll(".section-content")
+ .forEach((el) => contentObserver.observe(el));
+
+ const scrollHint = document.getElementById("scroll-hint");
+ if (scrollHint) {
+ window.addEventListener(
+ "scroll",
+ () => {
+ scrollHint.style.opacity = Math.max(0, 1 - window.scrollY / 200);
+ },
+ { passive: true },
+ );
+ }
+ }
+
+ // ===== PRIZE COUNTERS (easeOutExpo for satisfying deceleration) =====
+ function initPrizeCounters() {
+ const amounts = document.querySelectorAll(".prize-amount, .pool-amount");
+ let counted = false;
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting && !counted) {
+ counted = true;
+ amounts.forEach((el) => {
+ const target = parseInt(el.dataset.target);
+ if (target) animateCounter(el, target);
+ });
+ }
+ });
+ },
+ { threshold: 0.3 },
+ );
+
+ const prizesSection = document.getElementById("prizes-section");
+ if (prizesSection) observer.observe(prizesSection);
+ }
+
+ function animateCounter(el, target) {
+ const duration = 1500;
+ const start = performance.now();
+
+ function easeOutExpo(t) {
+ return t >= 1 ? 1 : 1 - Math.pow(2, -10 * t);
+ }
+
+ function step(now) {
+ const elapsed = now - start;
+ const progress = Math.min(elapsed / duration, 1);
+ const easedProgress = easeOutExpo(progress);
+ const current = Math.floor(easedProgress * target);
+ const prefix = el.dataset.prefix || "$";
+ el.textContent = prefix + current.toLocaleString("en-IN");
+ if (progress < 1) {
+ requestAnimationFrame(step);
+ } else {
+ const prefix = el.dataset.prefix || "$";
+ el.textContent = prefix + target.toLocaleString("en-IN");
+ }
+ }
+
+ requestAnimationFrame(step);
+ }
+
+ // ===== SCROLL PROGRESS BAR =====
+ function initScrollProgressBar() {
+ const bar = document.createElement("div");
+ bar.style.cssText = `
+ position: fixed; top: 0; left: 0; height: 3px; width: 0%;
+ background: ${RED};
+ z-index: 10000; transition: width 0.1s linear; pointer-events: none;
+ `;
+ document.body.appendChild(bar);
+
+ window.addEventListener(
+ "scroll",
+ () => {
+ const scrollTop = window.scrollY;
+ const docHeight =
+ document.documentElement.scrollHeight - window.innerHeight;
+ const progress = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
+ bar.style.width = progress + "%";
+ },
+ { passive: true },
+ );
+ }
+
+ // ===== ANNOUNCEMENTS =====
+ function initAnnouncements() {
+ if (typeof HACKX_CONFIG === "undefined") return;
+ const bar = document.getElementById("announcement-bar");
+ if (!bar) return;
+
+ function show() {
+ const msgs = HACKX_CONFIG.announcements;
+ bar.textContent = msgs[Math.floor(Math.random() * msgs.length)];
+ bar.classList.add("visible");
+ setTimeout(() => bar.classList.remove("visible"), 5000);
+ }
+
+ // Show normal announcements as before
+ setTimeout(show, 30000);
+ setInterval(show, 30000 + Math.random() * 15000);
+
+ // Show periodic hint every 2 minutes
+ function showHint() {
+ bar.textContent = 'Hint: Try dragging over certain numbers to progress in the game!';
+ bar.classList.add('visible');
+ setTimeout(() => bar.classList.remove('visible'), 7000);
+ }
+ setInterval(showHint, 2 * 60 * 1000); // every 2 minutes
+ }
+
+ // ===== CURSOR GLOW =====
+ function initCursorGlow() {
+ const glow = document.createElement("div");
+ glow.id = "cursor-glow";
+ glow.style.cssText = `
+ position: fixed; pointer-events: none; z-index: 9998;
+ width: 300px; height: 300px; border-radius: 50%;
+ background: radial-gradient(circle, rgba(255,23,68,0.06) 0%, transparent 70%);
+ transform: translate(-50%, -50%);
+ transition: opacity 0.3s;
+ `;
+ document.body.appendChild(glow);
+
+ document.addEventListener("mousemove", (e) => {
+ glow.style.left = e.clientX + "px";
+ glow.style.top = e.clientY + "px";
+ });
+
+ const hero = document.getElementById("hero-section");
+ if (hero) {
+ hero.addEventListener("mouseenter", () => {
+ glow.style.opacity = "0";
+ });
+ hero.addEventListener("mouseleave", () => {
+ glow.style.opacity = "1";
+ });
+ }
+ }
+
+ // ===== SUBTLE-BUT-WILD: Section Breathing =====
+ // Sections very slightly scale on a slow sine wave — barely perceptible life
+ function initSectionBreathing() {
+ const sections = document.querySelectorAll(".section-content");
+ if (!sections.length) return;
+ let time = 0;
+
+ function breathe() {
+ time += 0.008;
+ sections.forEach((section, i) => {
+ const phase = time + i * 0.7;
+ const scale = 1 + Math.sin(phase) * 0.002;
+ section.style.transform =
+ section.style.opacity === "0"
+ ? section.style.transform
+ : `scale(${scale})`;
+ });
+ requestAnimationFrame(breathe);
+ }
+
+ // Delay start so scroll fade-in finishes first
+ setTimeout(() => requestAnimationFrame(breathe), 2000);
+ }
+
+ // ===== SUBTLE-BUT-WILD: Border Glow on Scroll Proximity =====
+ // Section borders glow brighter as they approach the viewport center
+ function initBorderGlow() {
+ const sections = document.querySelectorAll(
+ ".info-card, .prize-card, .track-card, .track-block, .readout-row, .prize-entry, .timeline-item, .faq-item",
+ );
+ if (!sections.length) return;
+
+ sections.forEach((el) => {
+ el.style.transition =
+ "box-shadow 0.4s ease-out, border-color 0.4s ease-out";
+ });
+
+ function update() {
+ const viewportCenter = window.innerHeight / 2;
+ sections.forEach((el) => {
+ const rect = el.getBoundingClientRect();
+ const elCenter = rect.top + rect.height / 2;
+ const distance = Math.abs(elCenter - viewportCenter);
+ const maxDist = window.innerHeight * 0.6;
+ const proximity = Math.max(0, 1 - distance / maxDist);
+ const glowAlpha = proximity * 0.25;
+ const borderAlpha = 0.08 + proximity * 0.2;
+ el.style.boxShadow = `0 0 ${proximity * 20}px rgba(79, 209, 217, ${glowAlpha})`;
+ el.style.borderColor = `rgba(79, 209, 217, ${borderAlpha})`;
+ });
+ requestAnimationFrame(update);
+ }
+
+ requestAnimationFrame(update);
+ }
+
+ // ===== SUBTLE-BUT-WILD: Subtle Depth on Mouse =====
+ // Content shifts very slightly (max 3px) opposite to mouse, creating depth illusion
+ function initSubtleDepth() {
+ const elements = document.querySelectorAll(
+ ".section-content, .info-card, .prize-card, .track-block",
+ );
+ if (!elements.length) return;
+
+ let mouseX = window.innerWidth / 2;
+ let mouseY = window.innerHeight / 2;
+ let targetX = 0;
+ let targetY = 0;
+ let currentX = 0;
+ let currentY = 0;
+
+ document.addEventListener("mousemove", (e) => {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+ // Normalize to -1..1 from center
+ const nx = (mouseX / window.innerWidth - 0.5) * 2;
+ const ny = (mouseY / window.innerHeight - 0.5) * 2;
+ // Opposite direction, max 3px
+ targetX = -nx * 3;
+ targetY = -ny * 3;
+ });
+
+ function animate() {
+ // Smooth interpolation
+ currentX += (targetX - currentX) * 0.05;
+ currentY += (targetY - currentY) * 0.05;
+
+ elements.forEach((el) => {
+ const rect = el.getBoundingClientRect();
+ // Only apply to elements in viewport
+ if (rect.top < window.innerHeight && rect.bottom > 0) {
+ el.style.translate = `${currentX}px ${currentY}px`;
+ }
+ });
+ requestAnimationFrame(animate);
+ }
+
+ requestAnimationFrame(animate);
+ }
+
+ // ===== SUBTLE-BUT-WILD: Hover Warmth =====
+ // Subtle warm glow behind interactive elements on hover — box-shadow only, no transforms
+ function initHoverWarmth() {
+ const style = document.createElement("style");
+ style.textContent = `
+ .hover-warmth {
+ transition: box-shadow 0.35s ease-out;
+ }
+ .hover-warmth:hover {
+ box-shadow: 0 0 30px rgba(79, 209, 217, 0.12), 0 0 60px rgba(79, 209, 217, 0.06);
+ }
+ `;
+ document.head.appendChild(style);
+
+ document
+ .querySelectorAll(
+ ".readout-row, .prize-entry, .timeline-item, .faq-item, .track-block, .info-card, .prize-card",
+ )
+ .forEach((el) => {
+ el.classList.add("hover-warmth");
+ });
+ }
+
+ // ===== SUBTLE-BUT-WILD: Timeline Line Draw on Scroll =====
+ // The timeline vertical line "draws" downward as you scroll through the section
+ function initTimelineLineDraw() {
+ const timelineSection = document.getElementById("timeline-section");
+ if (!timelineSection) return;
+
+ const timelineLine = timelineSection.querySelector(".timeline-line");
+ if (!timelineLine) return;
+
+ // Store original height, then set to 0
+ const computedStyle = window.getComputedStyle(timelineLine);
+ const fullHeight = timelineLine.offsetHeight || timelineLine.scrollHeight;
+ timelineLine.style.height = "0px";
+ timelineLine.style.transition = "none";
+ timelineLine.style.overflow = "visible";
+
+ function update() {
+ const rect = timelineSection.getBoundingClientRect();
+ const sectionTop = rect.top;
+ const sectionHeight = rect.height;
+ const viewportHeight = window.innerHeight;
+
+ // Start drawing when section enters viewport, finish when section leaves
+ const scrollStart = viewportHeight * 0.8;
+ const scrollEnd = -sectionHeight * 0.2;
+ const progress = Math.max(
+ 0,
+ Math.min(1, (scrollStart - sectionTop) / (scrollStart - scrollEnd)),
+ );
+
+ timelineLine.style.height = progress * fullHeight + "px";
+ requestAnimationFrame(update);
+ }
+
+ requestAnimationFrame(update);
+ }
+
+ // ===== PERKS BG — Rising particles =====
+ function initPerksBgCanvas() {
+ const canvas = document.getElementById("perks-bg-canvas");
+ if (!canvas) return;
+ const ctx = canvas.getContext("2d");
+ let dots = [];
+
+ function resize() {
+ canvas.width = canvas.parentElement.offsetWidth;
+ canvas.height = canvas.parentElement.offsetHeight;
+ dots = [];
+ for (let i = 0; i < 30; i++) {
+ dots.push({
+ x: Math.random() * canvas.width,
+ y: Math.random() * canvas.height,
+ vy: -(Math.random() * 0.3 + 0.1),
+ size: Math.random() * 2 + 1,
+ alpha: Math.random() * 0.08 + 0.02,
+ });
+ }
+ }
+
+ function draw() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ dots.forEach((d) => {
+ d.y += d.vy;
+ if (d.y < -10) {
+ d.y = canvas.height + 10;
+ d.x = Math.random() * canvas.width;
+ }
+ ctx.beginPath();
+ ctx.arc(d.x, d.y, d.size, 0, Math.PI * 2);
+ ctx.fillStyle = `rgba(79, 209, 217, ${d.alpha})`;
+ ctx.fill();
+ });
+ requestAnimationFrame(draw);
+ }
+
+ resize();
+ window.addEventListener("resize", resize);
+ draw();
+ }
+
+ // ===== (unused) PERKS INTERACTIVE =====
+ function initPerksInteractive() {
+ const canvas = document.getElementById("perks-interactive");
+ if (!canvas) return;
+ const ctx = canvas.getContext("2d");
+ const tooltip = document.getElementById("perk-tooltip");
+
+ const perks = [
+ {
+ label: "₹3L+",
+ title: "PRIZES",
+ desc: "Cash prizes across both tracks — first and second place winners",
+ color: [79, 209, 217],
+ },
+ {
+ label: "24H",
+ title: "FOOD & CAFFEINE",
+ desc: "Meals, snacks, and unlimited coffee for the entire hackathon",
+ color: [0, 229, 255],
+ },
+ {
+ label: "1:1",
+ title: "MENTORSHIP",
+ desc: "Industry engineers and founders who've built at scale",
+ color: [124, 77, 255],
+ },
+ {
+ label: "200+",
+ title: "NETWORK",
+ desc: "Builders, designers, and dreamers from across the city",
+ color: [255, 214, 0],
+ },
+ {
+ label: "SWAG",
+ title: "MERCH & STICKERS",
+ desc: "Exclusive Hack X merch for all participants",
+ color: [79, 209, 217],
+ },
+ {
+ label: "CERT",
+ title: "CERTIFICATES",
+ desc: "Official CodeCell participation and winner certificates",
+ color: [0, 229, 255],
+ },
+ ];
+
+ let nodes = [];
+ let mouseX = -1000,
+ mouseY = -1000;
+ let hoveredNode = null;
+ let time = 0;
+
+ function resize() {
+ canvas.width = canvas.parentElement.offsetWidth;
+ canvas.height = canvas.parentElement.offsetHeight;
+ const cx = canvas.width / 2;
+ const cy = canvas.height / 2;
+ const radius = Math.min(canvas.width, canvas.height) * 0.28;
+
+ nodes = perks.map((p, i) => {
+ const angle = (i / perks.length) * Math.PI * 2 - Math.PI / 2;
+ return {
+ ...p,
+ baseX: cx + Math.cos(angle) * radius,
+ baseY: cy + Math.sin(angle) * radius,
+ x: cx + Math.cos(angle) * radius,
+ y: cy + Math.sin(angle) * radius,
+ r: 30,
+ angleOffset: angle,
+ orbitSpeed: 0.0003 + i * 0.00008,
+ floatOffset: Math.random() * Math.PI * 2,
+ };
+ });
+ }
+
+ function draw() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ time++;
+ const cx = canvas.width / 2;
+ const cy = canvas.height / 2;
+ const radius = Math.min(canvas.width, canvas.height) * 0.28;
+
+ hoveredNode = null;
+
+ // Update positions with gentle orbit + float
+ nodes.forEach((n, i) => {
+ const angle = n.angleOffset + time * n.orbitSpeed;
+ const float = Math.sin(time * 0.02 + n.floatOffset) * 8;
+ n.x = cx + Math.cos(angle) * radius + float;
+ n.y =
+ cy +
+ Math.sin(angle) * radius +
+ Math.cos(time * 0.015 + n.floatOffset) * 6;
+
+ // Check hover
+ const dx = mouseX - n.x;
+ const dy = mouseY - n.y;
+ if (Math.sqrt(dx * dx + dy * dy) < n.r + 15) {
+ hoveredNode = n;
+ }
+ });
+
+ // Draw connections between all nodes
+ for (let i = 0; i < nodes.length; i++) {
+ for (let j = i + 1; j < nodes.length; j++) {
+ const a = nodes[i],
+ b = nodes[j];
+ const dist = Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
+ const maxDist = radius * 2.2;
+ if (dist < maxDist) {
+ const alpha = (1 - dist / maxDist) * 0.12;
+ ctx.strokeStyle = `rgba(79, 209, 217, ${alpha})`;
+ ctx.lineWidth = 0.5;
+ ctx.beginPath();
+ ctx.moveTo(a.x, a.y);
+ ctx.lineTo(b.x, b.y);
+ ctx.stroke();
+ }
+ }
+ }
+
+ // Draw connection from mouse to nearby nodes
+ nodes.forEach((n) => {
+ const dx = mouseX - n.x;
+ const dy = mouseY - n.y;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < 200) {
+ const alpha = (1 - dist / 200) * 0.2;
+ ctx.strokeStyle = `rgba(${n.color.join(",")}, ${alpha})`;
+ ctx.lineWidth = 0.8;
+ ctx.beginPath();
+ ctx.moveTo(mouseX, mouseY);
+ ctx.lineTo(n.x, n.y);
+ ctx.stroke();
+ }
+ });
+
+ // Draw nodes
+ nodes.forEach((n) => {
+ const isHovered = n === hoveredNode;
+ const r = isHovered ? n.r + 8 : n.r;
+ const glowAlpha = isHovered ? 0.3 : 0.08;
+
+ // Outer glow
+ ctx.beginPath();
+ ctx.arc(n.x, n.y, r + 12, 0, Math.PI * 2);
+ ctx.fillStyle = `rgba(${n.color.join(",")}, ${glowAlpha})`;
+ ctx.fill();
+
+ // Circle
+ ctx.beginPath();
+ ctx.arc(n.x, n.y, r, 0, Math.PI * 2);
+ ctx.fillStyle = `rgba(10, 22, 40, ${isHovered ? 0.95 : 0.8})`;
+ ctx.fill();
+ ctx.strokeStyle = `rgba(${n.color.join(",")}, ${isHovered ? 0.8 : 0.3})`;
+ ctx.lineWidth = isHovered ? 2 : 1;
+ ctx.stroke();
+
+ // Label text
+ ctx.fillStyle = `rgba(${n.color.join(",")}, ${isHovered ? 1 : 0.7})`;
+ ctx.font = `bold ${isHovered ? 14 : 11}px 'Courier New', monospace`;
+ ctx.textAlign = "center";
+ ctx.textBaseline = "middle";
+ ctx.fillText(n.label, n.x, n.y);
+ });
+
+ // Tooltip
+ if (hoveredNode && tooltip) {
+ tooltip.innerHTML = `
+
${hoveredNode.label}
+
${hoveredNode.title}
+
${hoveredNode.desc}
+ `;
+ tooltip.classList.add("visible");
+ let tx = mouseX + 20;
+ let ty = mouseY - 20;
+ // Keep tooltip on screen
+ const rect = canvas.getBoundingClientRect();
+ if (tx + 260 > rect.width) tx = mouseX - 280;
+ tooltip.style.left = rect.left + tx + "px";
+ tooltip.style.top = rect.top + ty + "px";
+ } else if (tooltip) {
+ tooltip.classList.remove("visible");
+ }
+
+ requestAnimationFrame(draw);
+ }
+
+ canvas.addEventListener("mousemove", (e) => {
+ const rect = canvas.getBoundingClientRect();
+ mouseX = e.clientX - rect.left;
+ mouseY = e.clientY - rect.top;
+ });
+
+ canvas.addEventListener("mouseleave", () => {
+ mouseX = -1000;
+ mouseY = -1000;
+ });
+
+ resize();
+ window.addEventListener("resize", resize);
+ draw();
+ }
+
+ // ===== EASTER EGG: Triple-Click Secret Message =====
+ function initTripleClick() {
+ let clickCount = 0;
+ let clickTimer = null;
+
+ document.addEventListener("click", () => {
+ clickCount++;
+ if (clickTimer) clearTimeout(clickTimer);
+ clickTimer = setTimeout(() => {
+ clickCount = 0;
+ }, 400);
+
+ if (clickCount >= 3) {
+ clickCount = 0;
+ // Don't show during music dance experience
+ if (document.documentElement.classList.contains('theme-oscillating')) return;
+ showFlashMessage("YOU FOUND A SECRET. THE CODE REMEMBERS.", RED);
+ }
+ });
+ }
+
+ function showFlashMessage(text, color) {
+ const msg = document.createElement("div");
+ msg.textContent = text;
+ msg.style.cssText = `
+ position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
+ color: ${color}; font-family: 'Courier New', monospace; font-size: 18px;
+ z-index: 99999; pointer-events: none; text-align: center;
+ text-shadow: 0 0 20px ${color}; opacity: 0;
+ transition: opacity 0.3s ease; padding: 20px;
+ background: rgba(10, 22, 40, 0.85); border: 1px solid ${color};
+ `;
+ document.body.appendChild(msg);
+ requestAnimationFrame(() => {
+ msg.style.opacity = "1";
+ });
+ setTimeout(() => {
+ msg.style.opacity = "0";
+ setTimeout(() => msg.remove(), 300);
+ }, 2000);
+ }
+
+ // ===== EASTER EGG: Footer Copyright Hover (3s) =====
+ function initFooterCopyrightHover() {
+ const copy = document.querySelector(".footer-copy");
+ if (!copy) return;
+ let hoverTimer = null;
+ const original = copy.textContent;
+
+ copy.addEventListener("mouseenter", () => {
+ hoverTimer = setTimeout(() => {
+ copy.textContent =
+ "BUILT WITH SLEEPLESS NIGHTS AND TOO MUCH COFFEE \u2615";
+ copy.style.color = RED;
+ setTimeout(() => {
+ copy.textContent = original;
+ copy.style.color = "";
+ }, 3000);
+ }, 3000);
+ });
+
+ copy.addEventListener("mouseleave", () => {
+ if (hoverTimer) {
+ clearTimeout(hoverTimer);
+ hoverTimer = null;
+ }
+ });
+ }
+
+ // ===== EASTER EGG: CODECELL Matrix Cascade =====
+ function initCodecellMatrix() {
+ const logo = document.querySelector(".footer-logo");
+ if (!logo) return;
+
+ logo.style.cursor = "pointer";
+ logo.addEventListener("click", () => {
+ const overlay = document.createElement("canvas");
+ overlay.width = window.innerWidth;
+ overlay.height = window.innerHeight;
+ overlay.style.cssText = `
+ position: fixed; top: 0; left: 0; z-index: 99998;
+ pointer-events: none;
+ `;
+ document.body.appendChild(overlay);
+ const ctx = overlay.getContext("2d");
+ const word = "CODECELL";
+ const columns = Math.floor(overlay.width / 20);
+ const drops = new Array(columns).fill(0);
+ let frame = 0;
+
+ function draw() {
+ ctx.fillStyle = "rgba(10, 22, 40, 0.12)";
+ ctx.fillRect(0, 0, overlay.width, overlay.height);
+ ctx.font = "16px Courier New";
+
+ for (let i = 0; i < drops.length; i++) {
+ const ch = word[Math.floor(Math.random() * word.length)];
+ const alpha = Math.random() * 0.5 + 0.5;
+ ctx.fillStyle = `rgba(79, 209, 217, ${alpha})`;
+ ctx.fillText(ch, i * 20, drops[i] * 20);
+ if (drops[i] * 20 > overlay.height && Math.random() > 0.95)
+ drops[i] = 0;
+ drops[i]++;
+ }
+
+ frame++;
+ if (frame < 120) {
+ requestAnimationFrame(draw);
+ } else {
+ overlay.style.transition = "opacity 0.5s";
+ overlay.style.opacity = "0";
+ setTimeout(() => overlay.remove(), 500);
+ }
+ }
+ draw();
+ });
+ }
+
+ // ===== EASTER EGG: Bottom of Page Message =====
+ function initBottomMessage() {
+ const msg = document.createElement("div");
+ msg.innerHTML =
+ "> YOU'VE REACHED THE END OF THE DATA STREAM. SEE YOU AT HACK X.";
+ msg.style.cssText = `
+ position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%);
+ color: ${RED}; font-family: 'Courier New', monospace; font-size: 14px;
+ z-index: 99999; pointer-events: none; opacity: 0;
+ transition: opacity 0.8s ease; text-shadow: 0 0 10px ${RED};
+ white-space: nowrap;
+ `;
+ document.body.appendChild(msg);
+
+ window.addEventListener(
+ "scroll",
+ () => {
+ const scrollTop = window.scrollY;
+ const docHeight =
+ document.documentElement.scrollHeight - window.innerHeight;
+ if (docHeight > 0 && scrollTop >= docHeight - 5) {
+ msg.style.opacity = "1";
+ } else {
+ msg.style.opacity = "0";
+ }
+ },
+ { passive: true },
+ );
+ }
+
+ // ===== EASTER EGG: Type "10" Fireworks =====
+ function initTenFireworks() {
+ let buffer = "";
+ let mouseX = window.innerWidth / 2;
+ let mouseY = window.innerHeight / 2;
+
+ document.addEventListener("mousemove", (e) => {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+ });
+
+ document.addEventListener("keydown", (e) => {
+ buffer += e.key;
+ if (buffer.length > 10) buffer = buffer.slice(-10);
+ if (buffer.endsWith("10")) {
+ buffer = "";
+ spawnFireworks(mouseX, mouseY);
+ }
+ });
+ }
+
+ function spawnFireworks(cx, cy) {
+ const colors = [RED];
+ const canvas = document.createElement("canvas");
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ canvas.style.cssText =
+ "position:fixed;top:0;left:0;z-index:99997;pointer-events:none;";
+ document.body.appendChild(canvas);
+ const ctx = canvas.getContext("2d");
+
+ let particles = [];
+ for (let i = 0; i < 60; i++) {
+ const angle = Math.random() * Math.PI * 2;
+ const speed = Math.random() * 5 + 2;
+ particles.push({
+ x: cx,
+ y: cy,
+ vx: Math.cos(angle) * speed,
+ vy: Math.sin(angle) * speed - 2,
+ color: colors[Math.floor(Math.random() * colors.length)],
+ life: 1,
+ size: Math.random() * 4 + 2,
+ });
+ }
+
+ let frame = 0;
+ function draw() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ particles.forEach((p) => {
+ p.x += p.vx;
+ p.y += p.vy;
+ p.vy += 0.08;
+ p.life -= 0.015;
+ if (p.life > 0) {
+ ctx.beginPath();
+ ctx.arc(p.x, p.y, p.size * p.life, 0, Math.PI * 2);
+ ctx.fillStyle = p.color;
+ ctx.globalAlpha = p.life;
+ ctx.fill();
+ ctx.globalAlpha = 1;
+ }
+ });
+ particles = particles.filter((p) => p.life > 0);
+ frame++;
+ if (particles.length > 0 && frame < 180) {
+ requestAnimationFrame(draw);
+ } else {
+ canvas.remove();
+ }
+ }
+ draw();
+ }
+
+ // ===== EASTER EGG: Music Dance Experience =====
+ function initMusicDanceExperience() {
+ const audio = document.getElementById("secretMusic");
+ audio.volume = 0.3;
+ const stopBtn = document.getElementById("stopMusicBtn");
+ if (!audio || !stopBtn) return;
+
+ let typed = '';
+ let isPlaying = false;
+ let colorOscillationInterval = null;
+
+ function startColorOscillation() {
+ // Ensure we start on red (no class)
+ document.documentElement.classList.remove('theme-blue');
+ document.documentElement.classList.add('theme-oscillating');
+ let isBlue = false;
+ colorOscillationInterval = setInterval(() => {
+ isBlue = !isBlue;
+ if (isBlue) {
+ document.documentElement.classList.add('theme-blue');
+ } else {
+ document.documentElement.classList.remove('theme-blue');
+ }
+ }, 400);
+ }
+
+ function stopColorOscillation() {
+ if (colorOscillationInterval) {
+ clearInterval(colorOscillationInterval);
+ colorOscillationInterval = null;
+ }
+ // Reset back to red
+ document.documentElement.classList.remove('theme-blue');
+ document.documentElement.classList.remove('theme-oscillating');
+ }
+
+ // Container for music UI (title + stop button)
+ let musicUIContainer = null;
+ let lockOverlay = null;
+
+ function startMusic() {
+ if (isPlaying) return;
+ audio.play().catch(() => {
+ // Autoplay may block if user hasn't interacted yet.
+ });
+ isPlaying = true;
+
+ // Smooth scroll to top with JS animation, then lock
+ const scrollStart = window.scrollY || document.documentElement.scrollTop;
+ if (scrollStart > 0) {
+ const scrollDuration = 800;
+ const startTime = performance.now();
+ function animateScroll(now) {
+ const elapsed = now - startTime;
+ const progress = Math.min(elapsed / scrollDuration, 1);
+ // easeInOutQuad
+ const ease = progress < 0.5
+ ? 2 * progress * progress
+ : 1 - Math.pow(-2 * progress + 2, 2) / 2;
+ window.scrollTo(0, scrollStart * (1 - ease));
+ if (progress < 1) {
+ requestAnimationFrame(animateScroll);
+ } else {
+ document.documentElement.style.overflowY = 'hidden';
+ document.body.style.overflowY = 'hidden';
+ }
+ }
+ requestAnimationFrame(animateScroll);
+ } else {
+ document.documentElement.style.overflowY = 'hidden';
+ document.body.style.overflowY = 'hidden';
+ }
+
+ // Block interaction with game
+ lockOverlay = document.createElement('div');
+ lockOverlay.style.cssText = `
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
+ z-index: 99998; background: transparent; cursor: default;
+ `;
+ document.body.appendChild(lockOverlay);
+
+ // Disable game canvas and text selection
+ const heroSection = document.getElementById('hero-section');
+ if (heroSection) heroSection.style.pointerEvents = 'none';
+ document.body.style.userSelect = 'none';
+
+ // Create music UI container (centered on screen)
+ musicUIContainer = document.createElement('div');
+ musicUIContainer.style.cssText = `
+ position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
+ z-index: 99999; display: flex; flex-direction: column;
+ align-items: center; gap: 16px;
+ opacity: 0; transition: opacity 0.4s ease;
+ `;
+
+ // Title label (unclickable)
+ const titleLabel = document.createElement('div');
+ titleLabel.innerHTML = 'THE MUSIC
DANCE EXPERIENCE';
+ titleLabel.style.cssText = `
+ color: #ff0000ff; font-family: 'Geist Pixel', 'Courier New', monospace; font-size: 75px;
+ text-align: center; pointer-events: none; font-weight : bold;
+ text-shadow: 0 0 20px #ff0000ff; padding: 20px 40px;
+ background: rgba(10, 0, 8, 1.0); border: 1px solid #ff0000ff;
+ letter-spacing: 4px; text-transform: uppercase;
+ `;
+ musicUIContainer.appendChild(titleLabel);
+
+ // Style stop button
+ stopBtn.textContent = 'STOP THE MUSIC DANCE EXPERIENCE';
+ stopBtn.style.cssText = `
+ color: #ff0000ff; font-family: 'Courier New', monospace; font-size: 18px;
+ text-align: center; cursor: pointer;
+ text-shadow: 0 0 20px #ff0000ff; padding: 20px 40px;
+ background: rgba(10, 0, 8, 0.85); border: 1px solid #ff0000ff;
+ letter-spacing: 4px; text-transform: uppercase;
+ display: block;
+ `;
+ musicUIContainer.appendChild(stopBtn);
+
+ document.body.appendChild(musicUIContainer);
+ requestAnimationFrame(() => { musicUIContainer.style.opacity = '1'; });
+
+ startColorOscillation();
+ }
+
+ function stopMusic() {
+ audio.pause();
+ audio.currentTime = 0;
+ isPlaying = false;
+
+ // Unlock scroll
+ document.documentElement.style.overflowY = '';
+ document.body.style.overflowY = 'auto';
+
+ // Remove interaction blocker
+ if (lockOverlay) {
+ lockOverlay.remove();
+ lockOverlay = null;
+ }
+
+ // Re-enable game canvas and text selection
+ const heroSection = document.getElementById('hero-section');
+ if (heroSection) heroSection.style.pointerEvents = '';
+ document.body.style.userSelect = '';
+
+ // Fade out music UI container, then remove
+ if (musicUIContainer) {
+ musicUIContainer.style.opacity = '0';
+ const container = musicUIContainer;
+ setTimeout(() => {
+ container.remove();
+ stopBtn.style.display = 'none';
+ document.body.appendChild(stopBtn);
+ }, 400);
+ musicUIContainer = null;
+ } else {
+ stopBtn.style.display = 'none';
+ document.body.appendChild(stopBtn);
+ }
+
+ stopColorOscillation();
+ }
+
+ document.addEventListener("keydown", (e) => {
+ if (isPlaying) {
+ if (e.key === 'Escape')
+ stopMusic();
+ return;
+ }
+ if (!e.key || e.key.length !== 1) return;
+ typed += e.key.toLowerCase();
+ if (typed.length > 3) typed = typed.slice(-3);
+ if (typed === "mde") {
+ startMusic();
+ typed = "";
+ }
+ });
+
+ stopBtn.addEventListener("click", stopMusic);
+ audio.addEventListener("ended", stopMusic);
+ }
+
+
+ // ===== EASTER EGG: Track Tag Click Flash =====
+ function initTrackTagFlash() {
+ document.querySelectorAll(".track-tags span").forEach((tag) => {
+ tag.style.cursor = "pointer";
+ tag.style.transition = "all 0.15s ease";
+ tag.addEventListener("click", () => {
+ const origBg = tag.style.background;
+ const origColor = tag.style.color;
+ tag.style.background = "#4fd1d9";
+ tag.style.color = "#0a1628";
+ tag.style.boxShadow = "0 0 15px #4fd1d9";
+ setTimeout(() => {
+ tag.style.background = origBg;
+ tag.style.color = origColor;
+ tag.style.boxShadow = "";
+ }, 300);
+ });
+ });
+ }
+
+ // ===== EASTER EGG: Idle Message (30s) =====
+ function initIdleMessage() {
+ let idleTimer = null;
+ let shown = false;
+ const idleMsg = document.createElement("div");
+ idleMsg.style.cssText = `
+ position: fixed; bottom: 30px; left: 50%; transform: translateX(-50%);
+ color: ${RED}; font-family: 'Courier New', monospace; font-size: 14px;
+ z-index: 99999; pointer-events: none; opacity: 0;
+ transition: opacity 0.5s ease; text-shadow: 0 0 10px ${RED};
+ background: rgba(10, 22, 40, 0.9); padding: 12px 24px; border: 1px solid #4fd1d940;
+ white-space: nowrap;
+ `;
+ idleMsg.innerHTML =
+ '> STILL HERE? THE HACKATHON WON\'T WAIT.
[REGISTER] ';
+ document.body.appendChild(idleMsg);
+
+ function resetIdle() {
+ if (idleTimer) clearTimeout(idleTimer);
+ idleMsg.style.opacity = "0";
+ if (shown) return;
+ idleTimer = setTimeout(() => {
+ shown = true;
+ idleMsg.style.opacity = "1";
+ setTimeout(() => {
+ idleMsg.style.opacity = "0";
+ }, 5000);
+ }, 30000);
+ }
+
+ ["mousemove", "keydown", "scroll", "click", "touchstart"].forEach((evt) => {
+ document.addEventListener(evt, resetIdle, { passive: true });
+ });
+ resetIdle();
+ }
+
+ // ===== INTERACTION: Section Transitions — Horizontal Scan-Line Wipe =====
+ function initSectionTransitions() {
+ const sections = document.querySelectorAll(".section");
+ if (!sections.length) return;
+
+ const triggered = new Map();
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ const id = entry.target.id || entry.target.className;
+ const key =
+ id + "_" + (entry.boundingClientRect.top < 0 ? "up" : "down");
+ if (entry.isIntersecting && !triggered.has(key)) {
+ triggered.set(key, true);
+ const line = document.createElement("div");
+ line.style.cssText = `
+ position: absolute; top: 0; left: 0; height: 3px; width: 0%;
+ background: #4fd1d9; z-index: 9999; pointer-events: none;
+ transition: width 300ms ease-out;
+ `;
+ entry.target.style.position =
+ entry.target.style.position || "relative";
+ entry.target.appendChild(line);
+ requestAnimationFrame(() => {
+ line.style.width = "100%";
+ });
+ setTimeout(() => line.remove(), 400);
+ }
+ });
+ },
+ { threshold: 0.01 },
+ );
+
+ sections.forEach((s) => observer.observe(s));
+ }
+
+ // ===== INTERACTION: Data Stream — Ambient Falling Hex Characters =====
+ function initDataStream() {
+ if (window.innerWidth <= 1200) return;
+
+ const canvas = document.createElement("canvas");
+ canvas.width = 20;
+ canvas.height = window.innerHeight;
+ canvas.style.cssText = `
+ position: fixed; top: 0; right: 0; z-index: 9990;
+ pointer-events: none; width: 20px; height: 100vh;
+ `;
+ document.body.appendChild(canvas);
+ const ctx = canvas.getContext("2d");
+
+ const chars = "0123456789ABCDEF";
+ const drops = [];
+ for (let i = 0; i < 12; i++) {
+ drops.push({
+ x: Math.random() * 16 + 2,
+ y: Math.random() * canvas.height,
+ speed: Math.random() * 0.4 + 0.15,
+ char: chars[Math.floor(Math.random() * chars.length)],
+ changeTimer: 0,
+ });
+ }
+
+ function draw() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ ctx.font = "10px Courier New";
+ ctx.fillStyle = "rgba(79, 209, 217, 0.06)";
+
+ drops.forEach((d) => {
+ d.y += d.speed;
+ d.changeTimer++;
+ if (d.changeTimer > 60) {
+ d.char = chars[Math.floor(Math.random() * chars.length)];
+ d.changeTimer = 0;
+ }
+ if (d.y > canvas.height) {
+ d.y = -10;
+ d.x = Math.random() * 16 + 2;
+ }
+ ctx.fillText(d.char, d.x, d.y);
+ });
+
+ requestAnimationFrame(draw);
+ }
+
+ window.addEventListener("resize", () => {
+ canvas.height = window.innerHeight;
+ });
+
+ draw();
+ }
+
+ // ===== INTERACTION: Section Counter — Current Section Indicator =====
+ function initSectionCounter() {
+ const sections = document.querySelectorAll(".section");
+ if (!sections.length) return;
+
+ const total = String(sections.length).padStart(2, "0");
+ const counter = document.createElement("div");
+ counter.style.cssText = `
+ position: fixed; bottom: 16px; left: 16px; z-index: 9995;
+ font-family: 'Courier New', monospace; font-size: 9px;
+ color: rgba(79, 209, 217, 0.25); pointer-events: none;
+ letter-spacing: 2px;
+ `;
+ counter.textContent = "01 / " + total;
+ document.body.appendChild(counter);
+
+ const visibility = new Map();
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ visibility.set(entry.target, entry.intersectionRatio);
+ });
+
+ let maxRatio = 0;
+ let maxIndex = 0;
+ sections.forEach((s, i) => {
+ const ratio = visibility.get(s) || 0;
+ if (ratio > maxRatio) {
+ maxRatio = ratio;
+ maxIndex = i;
+ }
+ });
+
+ counter.textContent =
+ String(maxIndex + 1).padStart(2, "0") + " / " + total;
+ },
+ { threshold: [0, 0.25, 0.5, 0.75, 1] },
+ );
+
+ sections.forEach((s) => observer.observe(s));
+ }
+
+ // ===== INTERACTION: Mouse Ripple — Expanding Ring on Click =====
+ function initMouseRipple() {
+ const style = document.createElement("style");
+ style.textContent = `
+ @keyframes _rippleExpand {
+ 0% { width: 0; height: 0; opacity: 1; }
+ 100% { width: 100px; height: 100px; opacity: 0; }
+ }
+ ._mouse-ripple {
+ position: fixed; border-radius: 50%; pointer-events: none;
+ border: 1px solid rgba(79, 209, 217, 0.3);
+ animation: _rippleExpand 600ms ease-out forwards;
+ transform: translate(-50%, -50%);
+ z-index: 9996;
+ }
+ `;
+ document.head.appendChild(style);
+
+ let ripples = [];
+
+ document.addEventListener("click", (e) => {
+ // Skip hero/game section
+ const hero = document.getElementById("hero-section");
+ if (hero && hero.contains(e.target)) return;
+
+ if (ripples.length >= 3) {
+ const oldest = ripples.shift();
+ oldest.remove();
+ }
+
+ const ripple = document.createElement("div");
+ ripple.className = "_mouse-ripple";
+ ripple.style.left = e.clientX + "px";
+ ripple.style.top = e.clientY + "px";
+ document.body.appendChild(ripple);
+ ripples.push(ripple);
+
+ setTimeout(() => {
+ ripple.remove();
+ ripples = ripples.filter((r) => r !== ripple);
+ }, 600);
+ });
+ }
+
+ // ===== INTERACTION: Ambient Pulse — Page Breathing =====
+ function initAmbientPulse() {
+ document.body.style.transition = "background-color 2s ease-in-out";
+
+ function pulse() {
+ document.body.style.backgroundColor = "#0F0010";
+ setTimeout(() => {
+ document.body.style.backgroundColor = "#0a1628";
+ }, 2000);
+
+ const next = 8000 + Math.random() * 4000;
+ setTimeout(pulse, next);
+ }
+
+ setTimeout(pulse, 8000 + Math.random() * 4000);
+ }
+
+ // ===== INTERACTION: Hover Line Trace — Cyan Border Trace =====
+ function initHoverLineTrace() {
+ const style = document.createElement("style");
+ style.textContent = `
+ ._line-trace-wrap { position: relative; }
+ ._line-trace {
+ position: absolute; bottom: 0; left: 0;
+ height: 1px; width: 0; background: ${RED};
+ transition: width 400ms ease-out;
+ pointer-events: none;
+ }
+ ._line-trace-wrap:hover ._line-trace {
+ width: 100%;
+ }
+ `;
+ document.head.appendChild(style);
+
+ document
+ .querySelectorAll(".readout-row, .prize-entry, .timeline-item")
+ .forEach((el) => {
+ el.classList.add("_line-trace-wrap");
+ if (el.style.position === "" || el.style.position === "static") {
+ el.style.position = "relative";
+ }
+ const line = document.createElement("div");
+ line.className = "_line-trace";
+ el.appendChild(line);
+ });
+ }
+
+ // ===== INTERACTION: Reveal on Scroll — Glitch Text Entrance =====
+ function initRevealOnScroll() {
+ const headings = document.querySelectorAll(".glitch-text");
+ if (!headings.length) return;
+
+ headings.forEach((h) => {
+ h.style.opacity = "0";
+ h.style.transform = "translateY(40px)";
+ h.style.transition =
+ "opacity 800ms cubic-bezier(0.34, 1.56, 0.64, 1), transform 800ms cubic-bezier(0.34, 1.56, 0.64, 1)";
+ });
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ entry.target.style.opacity = "1";
+ entry.target.style.transform = "translateY(0)";
+ observer.unobserve(entry.target);
+ }
+ });
+ },
+ { threshold: 0.15 },
+ );
+
+ headings.forEach((h) => observer.observe(h));
+ }
+
+ // ===== TEAM MARQUEE =====
+ function initTeamGrid() {
+ const heads = [
+ {
+ name: "AMANDEEP SINGH",
+ role: "COMMITTEE HEAD",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Amandeep_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "VIRAJ BHARTIYA",
+ role: "COMMITTEE HEAD",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Viraj_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "OMIK ACHARYA",
+ role: "TECH HEAD",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Omik_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "ADITI SINGH",
+ role: "CREATIVE HEAD",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Aditi_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "RISHI SHANBHAG",
+ role: "MARKETING HEAD",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Rishi_2025-26.png",
+ profile: "#",
+ },
+ ];
+
+ const ty = [
+ {
+ name: "ADITYA BELGAONKAR",
+ role: "TECH",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Aditya_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "KUMAR TANAY",
+ role: "TECH",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Kumar_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "VIVEK JAIN",
+ role: "TECH",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Vivek_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "AKANKSHA AGROYA",
+ role: "CREATIVE",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Akanksha_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "AMRIT NIGAM",
+ role: "CREATIVE",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Amrit_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "CHAITANYA DHAMDHERE",
+ role: "MARKETING",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Chaitanya_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "DHARMIK CHANDEL",
+ role: "MARKETING",
+ dept: "IT/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Dharmik_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "SHREYANS TATIYA",
+ role: "MARKETING",
+ dept: "COMPS/TY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Shreyans_2025-26.png",
+ profile: "#",
+ },
+ ];
+
+ const sy = [
+ {
+ name: "ANMOL RAI",
+ role: "TECH",
+ dept: "COMPS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Anmol_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "ASHWERA HASAN",
+ role: "TECH",
+ dept: "COMPS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Ashwera_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "SAMAGRA AGARWAL",
+ role: "TECH",
+ dept: "COMPS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Samagra_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "SHANTANAV MUKHERJEE",
+ role: "TECH",
+ dept: "COMPS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Shantanav_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "TANUJ ADARKAR",
+ role: "TECH",
+ dept: "COMPS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Tanuj_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "VINAYAK PAI",
+ role: "TECH",
+ dept: "COMPS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Vinayak_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "AMEYA DEORE",
+ role: "CREATIVE",
+ dept: "CSBS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Ameya_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "PURVA POTE",
+ role: "CREATIVE",
+ dept: "CSBS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Purva_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "DIVYANSHI YADAV",
+ role: "CREATIVE",
+ dept: "COMPS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Divyanshi_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "DHANYA SHUKLA",
+ role: "CREATIVE",
+ dept: "COMPS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Dhanya_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "ARSHIA DANG",
+ role: "MARKETING",
+ dept: "IT/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Arshia_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "PARTH PANWAR",
+ role: "MARKETING",
+ dept: "AIDS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Parth_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "HARSHIL RAVARIYA",
+ role: "MARKETING",
+ dept: "AIDS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Harshil_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "SAMAIRA SHARMA",
+ role: "MARKETING",
+ dept: "IT/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Samaira_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "SHRAVIKA MHATRE",
+ role: "MARKETING",
+ dept: "VLSI/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Shravika_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "SRUSHTI TALANDAGE",
+ role: "MARKETING",
+ dept: "CSBS/SY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Srushti_2025-26.png",
+ profile: "#",
+ },
+ ];
+
+ const fy = [
+ {
+ name: "BHOUMIK SANGLE",
+ role: "TECH",
+ dept: "COMPS/FY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Bhoumik_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "DHRUV KUMAR",
+ role: "TECH",
+ dept: "COMPS/FY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Dhruv_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "PRANAV MENDON",
+ role: "TECH",
+ dept: "COMPS/FY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Pranav_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "ANCHITA SAHU",
+ role: "CREATIVE",
+ dept: "IT/FY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Anchita_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "MITALI PAUL",
+ role: "CREATIVE",
+ dept: "COMPS/FY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Mitali_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "RUDRAKSHI ACHARYYA",
+ role: "MARKETING",
+ dept: "COMPS/FY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Rudrakshi_2025-26.png",
+ profile: "#",
+ },
+ {
+ name: "YASH AGROYA",
+ role: "MARKETING",
+ dept: "IT/FY",
+ photo: "https://kjssecodecell.com/static/images/team-2025-26/Yash_2025-26.png",
+ profile: "#",
+ },
+ ];
+
+ function makeCard(member) {
+ const card = document.createElement("a");
+ card.className = "team-card";
+ card.href = member.profile;
+ card.target = "_blank";
+ card.rel = "noopener noreferrer";
+ card.setAttribute("aria-label", "Open " + member.name + " profile");
+
+ card.innerHTML = `
+
+
+
+
${member.name}
+
${member.role}
+ `;
+
+ return card;
+ }
+
+ function fillRow(rowId, members) {
+ const row = document.getElementById(rowId);
+ if (!row) return;
+ for (let pass = 0; pass < 2; pass++) {
+ members.forEach((m) => row.appendChild(makeCard(m)));
+ }
+ }
+
+ fillRow("team-row-heads", heads);
+ fillRow("team-row-ty", ty);
+ fillRow("team-row-sy", sy);
+ fillRow("team-row-fy", fy);
+ }
+
+ // ===== INTERACTION: Keyboard Whisper — Key Press Feedback =====
+ function initKeyboardWhisper() {
+ const style = document.createElement("style");
+ style.textContent = `
+ @keyframes _whisperFade {
+ 0% { opacity: 0.15; transform: translateY(0); }
+ 100% { opacity: 0; transform: translateY(-20px); }
+ }
+ ._key-whisper {
+ position: fixed; bottom: 40px; right: 24px;
+ font-family: 'Courier New', monospace; font-size: 80px;
+ color: #4fd1d9; pointer-events: none; z-index: 9994;
+ animation: _whisperFade 300ms ease-out forwards;
+ line-height: 1;
+ }
+ `;
+ document.head.appendChild(style);
+
+ let whispers = [];
+
+ document.addEventListener("keydown", (e) => {
+ // Skip if inside game section
+ const hero = document.getElementById("hero-section");
+ if (hero && hero.contains(document.activeElement)) return;
+ // Skip modifier/special keys
+ if (e.key.length > 1) return;
+
+ if (whispers.length >= 3) {
+ const oldest = whispers.shift();
+ oldest.remove();
+ }
+
+ const w = document.createElement("div");
+ w.className = "_key-whisper";
+ w.textContent = e.key;
+ w.style.bottom = 40 + whispers.length * 70 + "px";
+ document.body.appendChild(w);
+ whispers.push(w);
+
+ setTimeout(() => {
+ w.remove();
+ whispers = whispers.filter((x) => x !== w);
+ }, 300);
+ });
+ }
+})();
diff --git a/hackx/service-worker.js b/hackx/service-worker.js
new file mode 100644
index 00000000..7537fd0d
--- /dev/null
+++ b/hackx/service-worker.js
@@ -0,0 +1 @@
+addEventListener('fetch', event => {})
diff --git a/hackx/shaders/crt.frag.glsl b/hackx/shaders/crt.frag.glsl
new file mode 100644
index 00000000..4e3469f2
--- /dev/null
+++ b/hackx/shaders/crt.frag.glsl
@@ -0,0 +1,59 @@
+// much of this taken from: https://babylonjs.medium.com/retro-crt-shader-a-post-processing-effect-study-1cb3f783afbc
+
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+#define PI 3.1415926538
+
+// grab texcoords from vert shader
+varying vec2 vTexCoord;
+
+// our texture coming from p5
+uniform sampler2D u_tex;
+uniform vec2 u_resolution;
+vec2 curvature = vec2(4.5); //zoom level of curvature (lower = curvier)
+
+
+vec2 curveRemapUV(vec2 uv) {
+ // as we near the edge of our screen apply greater distortion using a cubic function
+ uv = uv * 2.0 - 1.0;
+ vec2 offset = abs(uv.yx) / vec2(curvature.x, curvature.y);
+ uv = uv + uv * offset * offset;
+ uv = uv * 0.5 + 0.5;
+ return uv;
+}
+
+void main() {
+ vec2 uv = vTexCoord;
+ uv.y = 1.0 - uv.y; //flip the incoming image texture
+
+ vec2 remappedUV = curveRemapUV(vec2(uv.xy));
+ vec4 baseColor = texture2D(u_tex, remappedUV);
+
+ float line_count = 400.0;
+ float opacity = 0.65;
+ float y_lines = sin(remappedUV.y * line_count * PI * 2.0);
+ y_lines = (y_lines * 0.5 + 0.5) * 0.9 + 0.1;
+ float x_lines = sin(remappedUV.x * line_count * PI * 2.0);
+ x_lines = (x_lines * 0.5 + 0.5) * 0.9 + 0.1;
+ vec4 scan_line = vec4(vec3(pow(y_lines, opacity)), 1.0);
+ vec4 scan_line_x = vec4(vec3(pow(x_lines, opacity)), 1.0);
+
+ // Boost brightness and bias the CRT phosphor toward the site cyan palette.
+ float avg = baseColor.r + baseColor.g + baseColor.b / 3.0;
+ if (avg > 0.5) {
+ baseColor *= vec4(vec3(0.3, 1.4, 1.5), 1.0) * 8.0;
+ } else {
+ baseColor *= vec4(vec3(0.2, 1.6, 1.8), 1.0) * 2.0;
+ }
+
+ baseColor *= scan_line;
+ baseColor *= scan_line_x;
+
+ if (remappedUV.x < 0.0 || remappedUV.y < 0.0 || remappedUV.x > 1.0 || remappedUV.y > 1.0) {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+ } else {
+ gl_FragColor = baseColor;
+ }
+}
diff --git a/hackx/shaders/crt.vert.glsl b/hackx/shaders/crt.vert.glsl
new file mode 100644
index 00000000..bc6651f1
--- /dev/null
+++ b/hackx/shaders/crt.vert.glsl
@@ -0,0 +1,19 @@
+// vert file and comments from adam ferriss
+// https://github.com/aferriss/p5jsShaderExamples
+
+// our vertex data
+attribute vec3 aPosition;
+attribute vec2 aTexCoord;
+
+varying vec2 vTexCoord;
+
+void main() {
+ vTexCoord = aTexCoord;
+
+ // copy the position data into a vec4, using 1.0 as the w component
+ vec4 positionVec4 = vec4(aPosition, 1.0);
+ positionVec4.xy = positionVec4.xy * 2.0 - 1.0;
+
+ // send the vertex information on to the fragment shader
+ gl_Position = positionVec4;
+}
\ No newline at end of file
diff --git a/hackx/sketch.js b/hackx/sketch.js
new file mode 100644
index 00000000..d23ecf4a
--- /dev/null
+++ b/hackx/sketch.js
@@ -0,0 +1,1194 @@
+let osn;
+
+// Total numbers to be collected
+let goal = 500;
+
+// Tracking the numbers
+var refined = [];
+var numbers = [];
+var cellSize, baseSize;
+var buffer; // set dynamically in setup based on screen size
+var cols, rows;
+
+// Info for refining
+let refining = false;
+let refineTX, refinteTY, refineBX, refineBY;
+
+// Logo text replaces lumon image
+const logoTextWidth = 180;
+
+let startTime = 0;
+let secondsSpentRefining = 0;
+let lastRefiningTimeStored = 0;
+
+const emojis = ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣"];
+
+// Info for "nope" state
+let nope = false;
+let nopeImg;
+let nopeTime = 0;
+
+// Info for 100% state
+let completed = false;
+let completedImg;
+let completedTime = 0;
+
+// Info for sharing
+let shared = false;
+let sharedImg;
+let sharedTime = 0;
+
+let shareDiv;
+
+// Hack X states
+let booting = true;
+let gameEnterAnim = 0; // 0 to 1 fade-in after boot
+let gameEnterStart = 0;
+let bootCharIndex = 0;
+let bootFrameCounter = 0;
+let bootGlitching = false;
+let bootGlitchStart = 0;
+let bootFadeAlpha = 255;
+
+let revealing = false;
+let revealText = "";
+let revealCharIndex = 0;
+let revealFrameCounter = 0;
+let revealPhase = "shake";
+let revealPhaseStart = 0;
+let revealsDone = [];
+
+let terminalOpen = false;
+var rainbowMode = false;
+let rainbowModeStart = 0;
+let logoFlash = false;
+let logoFlashStart = 0;
+
+// Visual effects
+let shakeAmount = 0;
+let particles = [];
+let glitchTimer = 0;
+let glitchSlices = [];
+let glitchFramesLeft = 0;
+
+// Mouse trail particles
+let mouseTrail = [];
+
+// Floating dust particles (background ambiance)
+let dustParticles = [];
+
+// Input buffers
+let keyBuffer = [];
+let exitBuffer = [];
+let konamiBuffer = [];
+const konamiCode = [
+ "ArrowUp",
+ "ArrowUp",
+ "ArrowDown",
+ "ArrowDown",
+ "ArrowLeft",
+ "ArrowRight",
+ "ArrowLeft",
+ "ArrowRight",
+ "b",
+ "a",
+];
+
+// for CRT Shader
+var shaderLayer, crtShader;
+var g; //p5 graphics instance
+var useShader;
+
+// Background and foreground colours — single-accent cyan theme.
+const mobilePalette = {
+ BG: "#0A1628",
+ FG: "#4fd1d9",
+ SELECT: "#e0f4f4",
+ LEVELS: {
+ WO: "#4fd1d9",
+ FC: "#4fd1d9",
+ DR: "#4fd1d9",
+ MA: "#4fd1d9",
+ },
+};
+
+const shaderPalette = {
+ BG: "#0A1628",
+ FG: "#3ab8c0",
+ SELECT: "#d0eef0",
+ LEVELS: {
+ WO: "#3ab8c0",
+ FC: "#3ab8c0",
+ DR: "#3ab8c0",
+ MA: "#3ab8c0",
+ },
+};
+
+var palette = mobilePalette;
+
+// holds filename, initial bin levels, coordinates
+let macrodataFile;
+
+// Add image svg
+let logoImg;
+
+function preload() {
+ nopeImg = loadImage("images/nope.png");
+ completedImg = loadImage("images/100.png");
+ sharedImg = loadImage("images/clipboard.png");
+ logoImg = loadImage('images/logo.svg')
+ crtShader = loadShader("shaders/crt.vert.glsl", "shaders/crt.frag.glsl");
+}
+
+function startOver(resetFile = false) {
+ // Track the amount of time
+ startTime = millis();
+
+ // Create the space
+ levelH = buffer * 1.7;
+ cellSize = (smaller - buffer * 2) / 10;
+ baseSize = cellSize * 0.33;
+ osn = new OpenSimplexNoise();
+ cols = floor(g.width / cellSize);
+ rows = floor((g.height - buffer * 2) / cellSize);
+
+ let wBuffer = g.width - cols * cellSize;
+ for (let j = 0; j < rows; j++) {
+ for (let i = 0; i < cols; i++) {
+ let x = i * cellSize + cellSize * 0.5 + wBuffer * 0.5;
+ let y = j * cellSize + cellSize * 0.5 + buffer;
+ // Initialize the number objects
+ numbers[i + j * cols] = new Data(x, y);
+ }
+ }
+
+ if (resetFile) {
+ macrodataFile.resetFile();
+ storeItem("secondsSpentRefining", 0);
+ secondsSpentRefining = 0;
+ lastRefiningTimeStored = 0;
+ }
+
+ // Refinement bins
+ for (let i = 0; i < 5; i++) {
+ const w = g.width / 5;
+ const binLevels = macrodataFile.storedBins
+ ? macrodataFile.storedBins[i]
+ : undefined;
+ refined[i] = new Bin(w, i, goal / 5, binLevels);
+ }
+
+ nopeTime = 0;
+ nope = false;
+ completed = false;
+ shared = false;
+ revealing = false;
+ revealsDone = [];
+ terminalOpen = false;
+ rainbowMode = false;
+ logoFlash = false;
+ particles = [];
+ mouseTrail = [];
+ shareDiv.hide();
+}
+
+var zoff = 0;
+var smaller;
+
+function setup() {
+ const cnv = createCanvas(windowWidth, windowHeight);
+ cnv.parent("game-container");
+ frameRate(30);
+
+ // create a downscaled graphics buffer to draw to, we'll upscale after applying crt shader
+ g = createGraphics(windowWidth, windowHeight);
+
+ // Scale buffer for mobile
+ smaller = min(g.width, g.height);
+ buffer = max(50, min(100, smaller * 0.12));
+
+ // We don't want to use shader on mobile
+ useShader = !isTouchScreenDevice();
+ // If the site is using the global CRT curvature pass (sections.js),
+ // skip the game's local CRT shader to keep one continuous "screen".
+ if (typeof window !== "undefined" && window.__HACKX_GLOBAL_CRT__ === true) {
+ useShader = false;
+ }
+
+ // The shader boosts colour values so we reset the palette if using shader
+ if (useShader) {
+ palette = shaderPalette;
+ }
+
+ // force pixel density to 1 to improve perf on retina screens
+ pixelDensity(1);
+
+ // p5 graphics element to draw our shader output to
+ shaderLayer = createGraphics(g.width, g.height, WEBGL);
+ shaderLayer.noStroke();
+ crtShader.setUniform("u_resolution", [g.width, g.height]);
+
+ smaller = min(g.width, g.height);
+
+ // Always start fresh on page load
+ localStorage.removeItem("hackx-data");
+ localStorage.removeItem("secondsSpentRefining");
+ macrodataFile = new MacrodataFile();
+ secondsSpentRefining = 0;
+
+ sharedImg.resize(smaller * 0.5, 0);
+ nopeImg.resize(smaller * 0.5, 0);
+ completedImg.resize(smaller * 0.5, 0);
+
+ // Width for the share 100% button
+ const shw = completedImg.width;
+ const shh = completedImg.height;
+ shareDiv = createDiv("");
+ shareDiv.hide();
+ shareDiv.position(g.width * 0.5 - shw * 0.5, g.height * 0.5 - shh * 0.5);
+ shareDiv.style("width", `${shw}px`);
+ shareDiv.style("height", `${shh}px`);
+ shareDiv.mousePressed(function () {
+ let thenumbers = "";
+ for (let r = 0; r < 5; r++) {
+ for (let c = 0; c < 5; c++) {
+ thenumbers += random(emojis);
+ }
+ thenumbers += "\n";
+ }
+ const timeStr = createTimeString(secondsSpentRefining);
+ const msg = `Refined ${macrodataFile.fileName} in ${timeStr} for ${HACKX_CONFIG.orgName}.
+${HACKX_CONFIG.eventName} // ${HACKX_CONFIG.tagline}
+${thenumbers}${HACKX_CONFIG.shareHashtags}
+${HACKX_CONFIG.shareUrl}`;
+
+ console.log("copy to clipboard!");
+ navigator.clipboard.writeText(msg);
+ shared = true;
+ });
+
+ // Initialize dust particles
+ for (let i = 0; i < 50; i++) {
+ dustParticles.push({
+ x: random(g.width),
+ y: random(g.height),
+ vx: random(-0.3, 0.3),
+ vy: random(-0.2, -0.05),
+ alpha: random(20, 60),
+ size: random(1, 3),
+ });
+ }
+
+ startOver();
+}
+
+function mousePressed() {
+ initAudio();
+ playClick();
+
+ // Logo click detection — progress bar left area where "CODECELL" label is
+ if (mouseX < g.width * 0.3 && mouseY < 55) {
+ logoFlash = true;
+ logoFlashStart = millis();
+ }
+
+ if (booting) {
+ booting = false;
+ gameEnterStart = millis();
+ document.body.style.overflowY = "auto";
+ return;
+ }
+
+ if (
+ !refining &&
+ !completed &&
+ !shared &&
+ !booting &&
+ !revealing &&
+ !terminalOpen
+ ) {
+ refineTX = mouseX;
+ refineTY = mouseY;
+ refineBX = mouseX;
+ refineBY = mouseY;
+ refining = true;
+ nope = false;
+ }
+}
+
+function mouseDragged() {
+ refineBX = mouseX;
+ refineBY = mouseY;
+}
+
+function mouseReleased() {
+ refining = false;
+ let countRed = 0;
+ let total = 0;
+ let refinery = [];
+ for (let num of numbers) {
+ if (num.inside(refineTX, refineTY, refineBX, refineBY)) {
+ if (num.refined) {
+ refinery.push(num);
+ countRed++;
+ }
+ total++;
+ }
+ num.turn(palette.FG);
+ num.refined = false;
+ }
+ // half of numbers must be refinable
+ if (countRed > 0.5 * total) {
+ const options = [];
+ for (let bin of refined) {
+ if (bin.count < bin.goal) {
+ options.push(bin);
+ }
+ }
+ const bin = random(options);
+ for (let num of refinery) {
+ num.refine(bin);
+ }
+ shakeAmount = 3;
+ playRefine();
+ } else {
+ refinery = [];
+ if (!completed && !shared) {
+ nope = true;
+ playNope();
+ }
+ nopeTime = millis();
+ }
+}
+
+let prevPercent;
+
+function draw() {
+ g.colorMode(RGB);
+ const globalCrtActive =
+ typeof window !== "undefined" && window.__HACKX_GLOBAL_CRT__ === true;
+
+ // Boot sequence gate
+ if (booting) {
+ drawBootSequence();
+ if (useShader && !globalCrtActive) {
+ shaderLayer.rect(0, 0, g.width, g.height);
+ shaderLayer.shader(crtShader);
+ crtShader.setUniform("u_tex", g);
+ background(palette.BG);
+ imageMode(CORNER);
+ image(shaderLayer, 0, 0, g.width, g.height);
+ } else {
+ image(g, 0, 0, g.width, g.height);
+ }
+ return;
+ }
+
+ // Game enter animation (numbers fade/scale in after boot)
+ if (gameEnterAnim < 1) {
+ gameEnterAnim = constrain((millis() - gameEnterStart) / 800, 0, 1);
+ }
+
+ // Rainbow mode timer (10 seconds)
+ if (rainbowMode && millis() - rainbowModeStart > 10000) {
+ rainbowMode = false;
+ }
+
+ let sum = 0;
+ for (let bin of refined) {
+ sum += bin.count;
+ }
+ let percent = sum / goal;
+
+ if (percent !== prevPercent) {
+ const bins = refined.map((bin) => bin.levels);
+ macrodataFile.updateProgress(bins);
+ prevPercent = percent;
+ }
+
+ // Milestone reveals
+ if (percent >= 0.25) triggerReveal(25);
+ if (percent >= 0.5) triggerReveal(50);
+ if (percent >= 0.75) triggerReveal(75);
+ if (percent >= 1.0) triggerReveal(100);
+
+ if (completed && shared) {
+ completed = false;
+ sharedTime = millis();
+ }
+
+ g.background(palette.BG);
+ g.textFont("Courier");
+
+ // Screen shake
+ if (shakeAmount > 0) {
+ g.push();
+ g.translate(
+ random(-shakeAmount, shakeAmount),
+ random(-shakeAmount, shakeAmount),
+ );
+ }
+
+ // Draw floating dust particles behind everything
+ drawDustParticles();
+
+ // Mouse trail particles
+ if (mouseX > 0 && mouseY > 0 && !booting) {
+ mouseTrail.push({ x: mouseX, y: mouseY, alpha: 150, size: random(2, 5) });
+ if (mouseTrail.length > 30) mouseTrail.shift();
+ }
+ drawMouseTrail();
+
+ drawTop(percent);
+ drawNumbers();
+ drawBottom();
+
+ drawBinned();
+ drawParticles();
+
+ // No top-right text — branding is in the progress bar now
+
+ // Logo flash — "CODECELL INDUSTRIES"
+ if (logoFlash) {
+ g.textFont("Courier");
+ g.textSize(smaller * 0.05);
+ g.textAlign(CENTER, CENTER);
+ g.fill(palette.FG);
+ g.noStroke();
+ g.text(HACKX_CONFIG.orgName, g.width * 0.5, g.height * 0.5);
+ if (millis() - logoFlashStart > 1000) {
+ logoFlash = false;
+ }
+ }
+
+ if (nope) {
+ g.imageMode(CENTER);
+ if (!useShader) g.tint(mobilePalette.FG);
+ g.image(nopeImg, g.width * 0.5, g.height * 0.5);
+ if (millis() - nopeTime > 1000) {
+ nope = false;
+ }
+ }
+
+ if (completed) {
+ g.imageMode(CENTER);
+ if (!useShader) g.tint(mobilePalette.FG);
+ g.image(completedImg, g.width * 0.5, g.height * 0.5);
+ }
+
+ if (shared) {
+ g.imageMode(CENTER);
+ if (!useShader) g.tint(mobilePalette.FG);
+ g.image(sharedImg, g.width * 0.5, g.height * 0.5);
+ if (millis() - sharedTime > 10000) {
+ startOver(true);
+ }
+ }
+
+ drawCursor(mouseX, mouseY);
+
+ if (shakeAmount > 0) {
+ g.pop();
+ shakeAmount = max(0, shakeAmount - 0.3);
+ }
+
+ if (revealing) {
+ drawReveal();
+ }
+
+ // Terminal overlay
+ if (terminalOpen) {
+ g.fill(0, 0, 0, 220);
+ g.noStroke();
+ g.rectMode(CORNER);
+ g.rect(g.width * 0.05, g.height * 0.1, g.width * 0.9, g.height * 0.8);
+
+ g.stroke(palette.FG);
+ g.strokeWeight(2);
+ g.noFill();
+ g.rect(g.width * 0.05, g.height * 0.1, g.width * 0.9, g.height * 0.8);
+
+ g.fill(palette.FG);
+ g.noStroke();
+ g.textFont("Courier");
+ g.textSize(smaller * 0.028);
+ g.textAlign(LEFT, TOP);
+
+ const tLines = HACKX_CONFIG.terminalLines;
+ const tLineH = smaller * 0.05;
+ const tx = g.width * 0.1;
+ const ty = g.height * 0.15;
+ for (let i = 0; i < tLines.length; i++) {
+ g.text(tLines[i], tx, ty + i * tLineH);
+ }
+
+ // Blinking cursor at bottom
+ if (frameCount % 20 < 10) {
+ g.fill(palette.FG);
+ g.rect(
+ tx,
+ ty + tLines.length * tLineH + 10,
+ smaller * 0.02,
+ smaller * 0.003,
+ );
+ }
+ }
+
+ // Idle glitch (desktop only)
+ if (!isTouchScreenDevice() && !booting && !revealing && !terminalOpen) {
+ glitchTimer++;
+ if (glitchTimer >= 350 && glitchFramesLeft <= 0) {
+ glitchFramesLeft = floor(random(2, 4));
+ glitchSlices = [];
+ for (let i = 0; i < 3; i++) {
+ glitchSlices.push({
+ y: random(g.height),
+ h: random(10, 40),
+ offset: random(-15, 15),
+ });
+ }
+ glitchTimer = floor(random(-100, 0)); // randomize next interval
+ }
+
+ if (glitchFramesLeft > 0) {
+ for (const s of glitchSlices) {
+ const slice = g.get(0, s.y, g.width, s.h);
+ g.image(slice, s.offset, s.y);
+ }
+ glitchFramesLeft--;
+ }
+ }
+
+ // Chromatic aberration during reveals (desktop only)
+ if (revealing && !isTouchScreenDevice()) {
+ const snap = g.get();
+ g.blendMode(ADD);
+ g.tint(255, 0, 0, 80);
+ g.image(snap, -3, 0);
+ g.tint(0, 0, 255, 80);
+ g.image(snap, 3, 0);
+ g.noTint();
+ g.blendMode(BLEND);
+ }
+
+ if (useShader && !globalCrtActive) {
+ shaderLayer.rect(0, 0, g.width, g.height);
+ shaderLayer.shader(crtShader);
+ crtShader.setUniform("u_tex", g);
+ background(palette.BG);
+ imageMode(CORNER);
+ image(shaderLayer, 0, 0, g.width, g.height);
+ } else {
+ image(g, 0, 0, g.width, g.height);
+ }
+
+ if (focused) {
+ secondsSpentRefining += deltaTime / 1000;
+ const roundedTime = round(secondsSpentRefining);
+ if (roundedTime % 5 == 0 && roundedTime != lastRefiningTimeStored) {
+ storeItem("secondsSpentRefining", secondsSpentRefining);
+ lastRefiningTimeStored = roundedTime;
+ }
+ }
+}
+
+function drawTop(percent) {
+ const y = 30;
+ const textSz = max(11, smaller * 0.02);
+
+ g.textFont("Courier");
+ g.noStroke();
+
+ // Left: Logo
+ if (logoImg) {
+ g.imageMode(CENTER);
+ if (!useShader) g.tint(palette.FG);
+
+ let logoWidth = 100;
+ let logoHeight = 100;
+ // Align the center of the image with the center of the text vertically
+ g.image(logoImg, g.width * 0.04 + logoWidth / 2, y + textSz / 2, logoWidth, logoHeight);
+ }
+
+ // Right: event info
+ g.textAlign(RIGHT, TOP);
+ g.textSize(max(9, smaller * 0.015));
+ const c = color(palette.FG);
+ c.setAlpha(180);
+ g.fill(c);
+ g.text(
+ HACKX_CONFIG.date + " // " + HACKX_CONFIG.location,
+ g.width * 0.96,
+ y,
+ );
+}
+
+function drawNumbers() {
+ g.rectMode(CENTER);
+ g.noFill();
+ g.strokeWeight(1);
+ g.line(0, buffer, g.width, buffer);
+ g.line(0, g.height - buffer, g.width, g.height - buffer);
+
+ let yoff = 0;
+
+ const inc = 0.2;
+ for (let i = 0; i < cols; i++) {
+ let xoff = 0;
+ for (let j = 0; j < rows; j++) {
+ let num = numbers[i + j * cols];
+ if (!num) return;
+
+ if (num.binIt) {
+ num.goBin();
+ num.show();
+ continue;
+ }
+
+ let n = osn.noise3D(xoff, yoff, zoff) - 0.4;
+ if (n < 0) {
+ n = 0;
+ num.goHome();
+ } else {
+ num.x += random(-1, 1);
+ num.y += random(-1, 1);
+ }
+
+ let sz = n * baseSize * 4 + baseSize;
+
+ let d = dist(mouseX, mouseY, num.x, num.y);
+
+ // Numbers flee from cursor more dramatically
+ if (d < g.width * 0.15) {
+ let angle = atan2(num.y - mouseY, num.x - mouseX);
+ let force = map(d, 0, g.width * 0.15, 3, 0);
+ num.x += cos(angle) * force;
+ num.y += sin(angle) * force;
+ } else {
+ num.goHome();
+ }
+
+ num.size(sz);
+ num.show();
+ xoff += inc;
+ }
+ yoff += inc;
+ }
+ zoff += 0.005;
+}
+
+function drawBottom() {
+ for (let i = 0; i < refined.length; i++) {
+ refined[i].show();
+ }
+
+ if (refining) {
+ g.push();
+ g.rectMode(CORNERS);
+ g.stroke(palette.FG);
+ g.noFill();
+ g.rect(refineTX, refineTY, refineBX, refineBY);
+
+ for (let num of numbers) {
+ if (
+ num.inside(refineTX, refineTY, refineBX, refineBY) &&
+ num.sz > baseSize
+ ) {
+ num.turn(palette.SELECT);
+ num.refined = true;
+ } else {
+ num.turn(palette.FG);
+ num.refined = false;
+ }
+ }
+ g.pop();
+ }
+
+ // Bottom bar — event info instead of hex coordinates
+ g.rectMode(CORNER);
+ g.fill(palette.FG);
+ g.rect(0, g.height - 20, g.width, 20);
+ g.fill(palette.BG);
+ g.textFont("Courier");
+ g.textAlign(CENTER, CENTER);
+ g.textSize(max(8, baseSize * 0.6));
+ let bottomText;
+ if (smaller < 500) {
+ bottomText = HACKX_CONFIG.eventName + " // " + HACKX_CONFIG.date;
+ } else {
+ bottomText =
+ HACKX_CONFIG.orgName +
+ " // " +
+ HACKX_CONFIG.eventName +
+ " // " +
+ HACKX_CONFIG.date +
+ " // " +
+ HACKX_CONFIG.shareUrl;
+ }
+ g.text(bottomText, g.width * 0.5, g.height - 10);
+}
+
+function drawBinned() {
+ for (let num of numbers) {
+ if (num.binIt) {
+ // Emit particle trail
+ if (num.binPause <= 0 && frameCount % 2 === 0) {
+ particles.push({
+ x: num.x + random(-2, 2),
+ y: num.y + random(-2, 2),
+ alpha: 200,
+ color: palette.FG,
+ });
+ }
+ num.show();
+ }
+ }
+}
+
+function drawParticles() {
+ for (let i = particles.length - 1; i >= 0; i--) {
+ const p = particles[i];
+ p.alpha -= 13;
+ if (p.alpha <= 0) {
+ particles.splice(i, 1);
+ continue;
+ }
+ g.noStroke();
+ const col = color(p.color);
+ col.setAlpha(p.alpha);
+ g.fill(col);
+ g.circle(p.x, p.y, 3);
+ }
+}
+
+function drawMouseTrail() {
+ for (let i = mouseTrail.length - 1; i >= 0; i--) {
+ const p = mouseTrail[i];
+ p.alpha -= 8;
+ if (p.alpha <= 0) {
+ mouseTrail.splice(i, 1);
+ continue;
+ }
+ g.noStroke();
+ const col = color(palette.FG);
+ col.setAlpha(p.alpha);
+ g.fill(col);
+ g.circle(p.x, p.y, p.size);
+ }
+}
+
+function drawDustParticles() {
+ for (let i = 0; i < dustParticles.length; i++) {
+ const d = dustParticles[i];
+ d.x += d.vx;
+ d.y += d.vy;
+
+ // Wrap around edges
+ if (d.x < 0) d.x = g.width;
+ if (d.x > g.width) d.x = 0;
+ if (d.y < 0) d.y = g.height;
+ if (d.y > g.height) d.y = 0;
+
+ // Subtle flickering alpha
+ let flickerAlpha = d.alpha + sin(millis() * 0.001 + i) * 10;
+ flickerAlpha = constrain(flickerAlpha, 5, 80);
+
+ g.noStroke();
+ const col = color(palette.FG);
+ col.setAlpha(flickerAlpha);
+ g.fill(col);
+ g.circle(d.x, d.y, d.size);
+ }
+}
+
+function drawFPS() {
+ textSize(24);
+ fill(palette.FG);
+ noStroke();
+ text(frameRate().toFixed(2), 50, 25);
+}
+
+function toggleShader() {
+ if (useShader) {
+ palette = mobilePalette;
+ } else {
+ palette = shaderPalette;
+ }
+ useShader = !useShader;
+}
+
+function drawCursor(xPos, yPos) {
+ // prevents the cursor appearing in top left corner on page load
+ if (xPos == 0 && yPos == 0) return;
+ g.push();
+ // this offset makes the box draw from point of cursor
+ g.translate(xPos + 10, yPos + 10);
+ g.scale(1.2);
+ g.fill(palette.BG);
+ g.stroke(palette.FG);
+ g.strokeWeight(3);
+ g.beginShape();
+ g.rotate(-PI / 5);
+ g.vertex(0, -10);
+ g.vertex(7.5, 10);
+ g.vertex(0, 5);
+ g.vertex(-7.5, 10);
+ g.endShape(CLOSE);
+ g.pop();
+}
+
+function drawBootSequence() {
+ g.background(palette.BG);
+ g.textFont("Courier");
+ g.fill(palette.FG);
+ g.noStroke();
+
+ const lines = HACKX_CONFIG.bootLines;
+ const totalChars = lines.join("").length + lines.length;
+ const lineHeight = smaller * 0.05;
+ const textSz = smaller * 0.035;
+ g.textSize(textSz);
+ g.textAlign(LEFT, TOP);
+
+ const startX = g.width * 0.1;
+ const startY = g.height * 0.3;
+
+ // Typing effect: increment char index every 3rd frame (~100ms at 30fps)
+ bootFrameCounter++;
+ if (bootFrameCounter >= 1) {
+ bootFrameCounter = 0;
+ bootCharIndex++;
+ }
+
+ // Render typed text
+ let charCount = 0;
+ for (let i = 0; i < lines.length; i++) {
+ let displayLine = "";
+ for (let c = 0; c < lines[i].length; c++) {
+ if (charCount < bootCharIndex) {
+ displayLine += lines[i][c];
+ charCount++;
+ } else {
+ break;
+ }
+ }
+ if (displayLine.length > 0) {
+ g.text(displayLine, startX, startY + i * lineHeight);
+ }
+ charCount++; // count the newline
+ if (charCount > bootCharIndex) break;
+ }
+
+ // Blinking cursor
+ if (frameCount % 15 < 8) {
+ let curCharCount = 0;
+ let curLine = 0;
+ let curCol = 0;
+ for (let i = 0; i < lines.length; i++) {
+ if (curCharCount + lines[i].length >= bootCharIndex) {
+ curLine = i;
+ curCol = bootCharIndex - curCharCount;
+ break;
+ }
+ curCharCount += lines[i].length + 1;
+ curLine = i + 1;
+ curCol = 0;
+ }
+ g.rect(
+ startX + curCol * textSz * 0.6,
+ startY + curLine * lineHeight,
+ textSz * 0.6,
+ textSz,
+ );
+ }
+
+ // Check if all text is typed
+ if (bootCharIndex >= totalChars) {
+ if (!bootGlitching) {
+ bootGlitching = true;
+ bootGlitchStart = millis();
+ }
+
+ const elapsed = millis() - bootGlitchStart;
+ if (elapsed > 400) {
+ // Glitch effect: random horizontal slices
+ if (elapsed < 800) {
+ for (let i = 0; i < 5; i++) {
+ const sliceY = random(g.height);
+ const sliceH = random(10, 40);
+ const offsetX = random(-30, 30);
+ const slice = g.get(0, sliceY, g.width, sliceH);
+ g.image(slice, offsetX, sliceY);
+ }
+ }
+
+ // Brightness flicker during glitch
+ if (elapsed > 400 && elapsed < 800 && frameCount % 3 === 0) {
+ g.fill(255, 255, 255, random(20, 80));
+ g.rectMode(CORNER);
+ g.rect(0, 0, g.width, g.height);
+ }
+
+ // Fade out
+ if (elapsed > 700) {
+ bootFadeAlpha = map(elapsed, 700, 1000, 255, 0);
+ bootFadeAlpha = constrain(bootFadeAlpha, 0, 255);
+ const c = color(palette.FG);
+ g.fill(red(c), green(c), blue(c), bootFadeAlpha);
+ }
+
+ // End boot
+ if (elapsed > 1000) {
+ booting = false;
+ gameEnterStart = millis();
+ document.body.style.overflowY = "auto";
+ }
+ }
+ }
+}
+
+function drawReveal() {
+ const elapsed = millis() - revealPhaseStart;
+
+ switch (revealPhase) {
+ case "shake":
+ shakeAmount = 5;
+ if (elapsed > 300) {
+ revealPhase = "glitch";
+ revealPhaseStart = millis();
+ revealCharIndex = 0;
+ revealFrameCounter = 0;
+ }
+ break;
+
+ case "glitch":
+ for (let i = 0; i < 4; i++) {
+ const sliceY = random(g.height);
+ const sliceH = random(10, 50);
+ const offsetX = random(-20, 20);
+ const slice = g.get(0, sliceY, g.width, sliceH);
+ g.image(slice, offsetX, sliceY);
+ }
+ if (elapsed > 500) {
+ revealPhase = "typing";
+ revealPhaseStart = millis();
+ }
+ break;
+
+ case "typing": {
+ g.fill(0, 0, 0, 200);
+ g.noStroke();
+ g.rectMode(CORNER);
+ g.rect(0, 0, g.width, g.height);
+
+ g.fill(palette.FG);
+ g.textFont("Courier");
+ g.textSize(smaller * 0.035);
+ g.textAlign(CENTER, CENTER);
+
+ revealFrameCounter++;
+ if (revealFrameCounter >= 3) {
+ revealFrameCounter = 0;
+ revealCharIndex++;
+ }
+
+ const displayText = revealText.substring(
+ 0,
+ min(revealCharIndex, revealText.length),
+ );
+
+ // Word wrap
+ const maxWidth = g.width * 0.8;
+ const words = displayText.split(" ");
+ let lines = [""];
+ let lineIdx = 0;
+ for (const word of words) {
+ const testLine = lines[lineIdx] + (lines[lineIdx] ? " " : "") + word;
+ if (g.textWidth(testLine) > maxWidth && lines[lineIdx]) {
+ lineIdx++;
+ lines[lineIdx] = word;
+ } else {
+ lines[lineIdx] = testLine;
+ }
+ }
+
+ const lineH = smaller * 0.06;
+ const totalH = lines.length * lineH;
+ for (let i = 0; i < lines.length; i++) {
+ g.text(
+ lines[i],
+ g.width * 0.5,
+ g.height * 0.5 - totalH / 2 + i * lineH,
+ );
+ }
+
+ if (revealCharIndex >= revealText.length) {
+ if (millis() - revealPhaseStart > 500) {
+ revealPhase = "hold";
+ revealPhaseStart = millis();
+ }
+ }
+ break;
+ }
+
+ case "hold": {
+ g.fill(0, 0, 0, 200);
+ g.noStroke();
+ g.rectMode(CORNER);
+ g.rect(0, 0, g.width, g.height);
+
+ g.fill(palette.FG);
+ g.textFont("Courier");
+ g.textSize(smaller * 0.035);
+ g.textAlign(CENTER, CENTER);
+
+ const holdWords = revealText.split(" ");
+ let holdLines = [""];
+ let hLineIdx = 0;
+ const hMaxW = g.width * 0.8;
+ for (const word of holdWords) {
+ const testLine =
+ holdLines[hLineIdx] + (holdLines[hLineIdx] ? " " : "") + word;
+ if (g.textWidth(testLine) > hMaxW && holdLines[hLineIdx]) {
+ hLineIdx++;
+ holdLines[hLineIdx] = word;
+ } else {
+ holdLines[hLineIdx] = testLine;
+ }
+ }
+ const hLineH = smaller * 0.06;
+ const hTotalH = holdLines.length * hLineH;
+ for (let i = 0; i < holdLines.length; i++) {
+ g.text(
+ holdLines[i],
+ g.width * 0.5,
+ g.height * 0.5 - hTotalH / 2 + i * hLineH,
+ );
+ }
+
+ if (elapsed > 3000) {
+ revealPhase = "glitchout";
+ revealPhaseStart = millis();
+ }
+ break;
+ }
+
+ case "glitchout":
+ for (let i = 0; i < 4; i++) {
+ const sliceY = random(g.height);
+ const sliceH = random(10, 50);
+ const offsetX = random(-20, 20);
+ const slice = g.get(0, sliceY, g.width, sliceH);
+ g.image(slice, offsetX, sliceY);
+ }
+ if (elapsed > 500) {
+ revealPhase = "done";
+ revealing = false;
+ // If 100% reveal just ended, trigger completed state
+ if (revealsDone.includes(100)) {
+ completed = true;
+ completedTime = millis() - startTime;
+ shareDiv.show();
+ }
+ }
+ break;
+ }
+}
+
+function triggerReveal(percent) {
+ if (revealsDone.includes(percent)) return;
+ if (revealing || booting || terminalOpen) return;
+
+ // Mid-drag edge case
+ if (refining) {
+ refining = false;
+ for (let num of numbers) {
+ num.turn(palette.FG);
+ num.refined = false;
+ }
+ }
+
+ revealsDone.push(percent);
+ revealing = true;
+ revealText = HACKX_CONFIG.reveals[percent].text;
+ revealCharIndex = 0;
+ revealFrameCounter = 0;
+ revealPhase = "shake";
+ revealPhaseStart = millis();
+ shakeAmount = 5;
+ playMilestone();
+}
+
+function keyPressed() {
+ // Letter keys for hackx/exit buffers
+ if (key.length === 1 && key.match(/[a-z]/i)) {
+ const k = key.toLowerCase();
+
+ if (terminalOpen) {
+ exitBuffer.push(k);
+ if (exitBuffer.length > 4) exitBuffer.shift();
+ if (exitBuffer.join("") === "exit") {
+ terminalOpen = false;
+ keyBuffer = [];
+ }
+ } else if (!booting && !revealing) {
+ keyBuffer.push(k);
+ if (keyBuffer.length > 5) keyBuffer.shift();
+ if (keyBuffer.join("") === "hackx") {
+ terminalOpen = true;
+ exitBuffer = [];
+ }
+ }
+ }
+
+ // Konami code tracking
+ const konamiKey = key.length > 1 ? key : key.toLowerCase();
+ konamiBuffer.push(konamiKey);
+ if (konamiBuffer.length > 10) konamiBuffer.shift();
+ if (
+ konamiBuffer.length === 10 &&
+ konamiBuffer.every((k, i) => k === konamiCode[i])
+ ) {
+ rainbowMode = true;
+ rainbowModeStart = millis();
+ konamiBuffer = [];
+ }
+}
+
+function windowResized(ev) {
+ resizeCanvas(windowWidth, windowHeight);
+ g.resizeCanvas(windowWidth, windowHeight);
+ shaderLayer.resizeCanvas(windowWidth, windowHeight);
+ crtShader.setUniform("u_resolution", [g.width, g.height]);
+
+ smaller = min(g.width, g.height);
+ buffer = max(50, min(100, smaller * 0.12));
+
+ sharedImg.resize(smaller * 0.5, 0);
+ nopeImg.resize(smaller * 0.5, 0);
+ completedImg.resize(smaller * 0.5, 0);
+
+ refined.forEach((bin) => bin.resize(g.width / refined.length));
+
+ cellSize = (smaller - buffer * 2) / 10;
+ baseSize = cellSize * 0.33;
+
+ cols = floor(g.width / cellSize);
+ rows = floor((g.height - buffer * 2) / cellSize);
+ let wBuffer = g.width - cols * cellSize;
+
+ for (let j = 0; j < rows; j++) {
+ for (let i = 0; i < cols; i++) {
+ let x = i * cellSize + cellSize * 0.5 + wBuffer * 0.5;
+ let y = j * cellSize + cellSize * 0.5 + buffer;
+ const numToUpdate = numbers[i + j * cols];
+ if (numToUpdate) numToUpdate.resize(x, y);
+ }
+ }
+
+ // Re-scatter dust particles across new dimensions
+ for (let i = 0; i < dustParticles.length; i++) {
+ dustParticles[i].x = random(g.width);
+ dustParticles[i].y = random(g.height);
+ }
+}
diff --git a/hackx/style.css b/hackx/style.css
new file mode 100644
index 00000000..a7bcbdd9
--- /dev/null
+++ b/hackx/style.css
@@ -0,0 +1,1895 @@
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+}
+
+html {
+ scroll-behavior: smooth;
+ scrollbar-width: thin;
+ scrollbar-color: #4fd1d9 #0a1628;
+}
+
+body {
+ background-color: #0a1628;
+ color: #4fd1d9;
+ font-family: "Geist Pixel", "Courier New", Courier, monospace;
+ overflow-x: hidden;
+ overflow-y: hidden;
+ letter-spacing: 0.04em;
+ --accent: #4fd1d9;
+ --red: var(--accent);
+ --cyan: var(--accent);
+ --purple: var(--accent);
+ --gold: var(--accent);
+ --text: #a0c4cc;
+ --text-dim: #5a8a94;
+ --bg: #0a1628;
+ cursor: none;
+}
+
+/* Hide system cursor across interactive elements */
+a,
+button,
+input,
+textarea,
+select,
+label {
+ cursor: none;
+}
+
+/* TV CRT Vignette Overlay */
+.vignette-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ pointer-events: none;
+ z-index: 9999;
+ background: radial-gradient(ellipse at center,
+ transparent 50%,
+ rgba(0, 0, 0, 0.3) 75%,
+ rgba(0, 0, 0, 0.95) 100%);
+ box-shadow: inset 0 0 12vmin rgba(0, 0, 0, 0.9);
+}
+
+/* Scan-line overlay removed — was causing compositing overhead */
+
+::-webkit-scrollbar {
+ width: 6px;
+}
+
+::-webkit-scrollbar-track {
+ background: #0a1628;
+}
+
+::-webkit-scrollbar-thumb {
+ background: #4fd1d9;
+}
+
+/* ===== KEYFRAMES ===== */
+
+@keyframes breathe {
+
+ 0%,
+ 100% {
+ border-color: #4fd1d920;
+ }
+
+ 50% {
+ border-color: #4fd1d9a0;
+ }
+}
+
+@keyframes flicker {
+
+ 0%,
+ 100% {
+ opacity: 1;
+ }
+
+ 92% {
+ opacity: 1;
+ }
+
+ 93% {
+ opacity: 0.8;
+ }
+
+ 94% {
+ opacity: 1;
+ }
+
+ 96% {
+ opacity: 0.9;
+ }
+
+ 97% {
+ opacity: 1;
+ }
+}
+
+@keyframes subtlePulse {
+
+ 0%,
+ 100% {
+ opacity: 0.6;
+ }
+
+ 50% {
+ opacity: 1;
+ }
+}
+
+@keyframes scanDown {
+ 0% {
+ background-position: 0 -100vh;
+ }
+
+ 100% {
+ background-position: 0 100vh;
+ }
+}
+
+@keyframes pulse-border {
+
+ 0%,
+ 100% {
+ border-color: #4fd1d9;
+ box-shadow: 0 0 5px #4fd1d930;
+ }
+
+ 50% {
+ border-color: #ff5252;
+ box-shadow: 0 0 20px #4fd1d960;
+ }
+}
+
+@keyframes bounce {
+
+ 0%,
+ 100% {
+ transform: translateX(-50%) translateY(0);
+ }
+
+ 50% {
+ transform: translateX(-50%) translateY(10px);
+ }
+}
+
+@keyframes faq-reveal {
+ 0% {
+ opacity: 0;
+ transform: translateX(-5px);
+ }
+
+ 50% {
+ opacity: 0.5;
+ transform: translateX(3px);
+ }
+
+ 100% {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+/* ===== SECTIONS ===== */
+.section {
+ position: relative;
+ min-height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+}
+
+.section canvas {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 0;
+}
+
+.section-content {
+ position: relative;
+ z-index: 1;
+ max-width: 1000px;
+ width: 90%;
+ margin: 0 auto;
+ padding: 120px 20px;
+}
+
+/* ===== HERO SECTION ===== */
+#hero-section {
+ height: 100vh;
+ position: relative;
+ display: block;
+ padding: 0;
+}
+
+#game-container {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+}
+
+#game-container>canvas:first-of-type {
+ display: block;
+ touch-action: none;
+ cursor: none;
+}
+
+#scroll-hint {
+ position: absolute;
+ bottom: 40px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 10;
+ color: var(--cyan);
+ font-family: "Geist Pixel", "Courier New", monospace;
+ font-size: 11px;
+ letter-spacing: 4px;
+ text-transform: uppercase;
+ animation: bounce 2s infinite;
+ pointer-events: none;
+}
+
+/* ===== GLITCH TEXT ===== */
+.glitch-text {
+ font-size: clamp(40px, 8vw, 120px);
+ font-weight: bold;
+ letter-spacing: 0.15em;
+ color: #4fd1d9;
+ text-transform: uppercase;
+ margin-bottom: 40px;
+ line-height: 1;
+ text-align: center;
+ position: relative;
+ text-shadow:
+ 0 0 40px #4fd1d940,
+ 0 0 80px #4fd1d920;
+}
+
+.glitch-text::before,
+.glitch-text::after {
+ display: none !important;
+ content: none !important;
+}
+
+/* ===== ABOUT SECTION ===== */
+#about-section {
+ border-top: 2px solid #4fd1d920;
+}
+
+.section-desc {
+ font-size: clamp(13px, 1.8vw, 16px);
+ line-height: 2;
+ max-width: 640px;
+ margin: 0 auto 60px;
+ text-align: left;
+ color: var(--text);
+ border-left: 2px solid #4fd1d940;
+ padding-left: 20px;
+}
+
+.about-layout {
+ display: flex;
+ gap: 60px;
+ align-items: center;
+}
+
+.about-left {
+ flex: 1;
+}
+
+.about-left .glitch-text {
+ text-align: left;
+ margin-bottom: 12px;
+}
+
+.about-tagline {
+ font-size: 11px;
+ letter-spacing: 5px;
+ color: var(--cyan);
+ margin-bottom: 24px;
+ opacity: 0.8;
+}
+
+.about-desc {
+ font-size: 14px;
+ line-height: 1.8;
+ color: var(--text);
+ margin-bottom: 30px;
+ max-width: 420px;
+}
+
+.about-cta {
+ display: inline-block;
+ font-size: 11px;
+ letter-spacing: 3px;
+ color: var(--red);
+ text-decoration: none;
+ border: 1px solid var(--red);
+ padding: 12px 24px;
+ transition: all 0.3s ease;
+}
+
+.about-cta:hover {
+ background: var(--red);
+ color: var(--bg);
+ box-shadow:
+ 0 0 20px #4fd1d950,
+ 0 0 40px #4fd1d920;
+}
+
+.about-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ margin-bottom: 24px;
+}
+
+.about-tags span {
+ font-size: 10px;
+ letter-spacing: 2px;
+ padding: 8px 16px;
+ border: 1px solid #4fd1d940;
+ color: var(--red);
+ text-transform: uppercase;
+ transition: all 0.3s ease;
+ cursor: default;
+}
+
+.about-tags span:hover {
+ background: var(--red);
+ color: var(--bg);
+ box-shadow: 0 0 12px #4fd1d930;
+}
+
+.about-left .apply-button {
+ margin-top: 18px;
+ min-height: 44px;
+ display: inline-block;
+}
+
+.about-left .apply-button > iframe {
+ border: 0;
+}
+
+.about-right {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 4px;
+ flex-shrink: 0;
+ width: 340px;
+}
+
+.about-model {
+ width: 420px;
+ height: 420px;
+ border: none;
+ background: transparent;
+ box-shadow: none;
+}
+
+.about-model:focus {
+ outline: none;
+}
+
+.about-stat {
+ border: 1px solid #4fd1d918;
+ padding: 32px 20px;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ aspect-ratio: 1;
+ opacity: 0;
+ transform: translateY(20px);
+ transition:
+ opacity 0.6s ease-out,
+ border-color 0.3s ease,
+ background 0.3s ease,
+ box-shadow 0.3s ease,
+ transform 0.4s ease-out;
+}
+
+.about-stat.visible {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.about-stat:hover {
+ border-color: #4fd1d940;
+ background: #ff174808;
+ box-shadow: 0 0 12px #4fd1d915;
+ transform: translateY(-5px);
+}
+
+.about-stat-value {
+ font-size: clamp(16px, 2.5vw, 22px);
+ font-weight: bold;
+ letter-spacing: 2px;
+ color: var(--red);
+ margin-bottom: 6px;
+ text-shadow: 0 0 10px #4fd1d925;
+}
+
+.about-stat-label {
+ font-size: 8px;
+ letter-spacing: 4px;
+ color: var(--text-dim);
+ text-transform: uppercase;
+}
+
+/* ===== TRACKS SECTION — Full-width Stacked Blocks ===== */
+#tracks-section {
+ border-top: 2px solid #4fd1d920;
+}
+
+.track-block {
+ position: relative;
+ border-top: 1px solid #4fd1d925;
+ border-bottom: 1px solid #4fd1d925;
+ overflow: hidden;
+ min-height: 360px;
+ margin-bottom: -1px;
+ transition: all 0.4s ease;
+}
+
+.track-block:hover {
+ background: #ff174806;
+ border-color: #4fd1d990;
+}
+
+.track-block canvas {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 0;
+}
+
+.track-content {
+ position: relative;
+ z-index: 1;
+ padding: 60px 40px;
+ max-width: 700px;
+}
+
+.track-number {
+ font-size: clamp(64px, 10vw, 120px);
+ font-weight: bold;
+ color: #4fd1d910;
+ line-height: 1;
+ letter-spacing: -0.04em;
+ margin-bottom: 8px;
+ pointer-events: none;
+}
+
+.track-content h2 {
+ font-size: clamp(28px, 5vw, 52px);
+ letter-spacing: 0.12em;
+ margin-bottom: 6px;
+ line-height: 1.1;
+ text-shadow: 0 0 30px #4fd1d920;
+}
+
+.track-subtitle {
+ font-size: 10px;
+ letter-spacing: 4px;
+ color: var(--cyan);
+ margin-bottom: 24px;
+ text-transform: uppercase;
+ opacity: 0.8;
+}
+
+.track-subtitle::before {
+ content: "// ";
+ color: var(--cyan);
+ opacity: 0.5;
+}
+
+.track-content p {
+ font-size: 13px;
+ line-height: 1.9;
+ color: var(--text);
+ margin-bottom: 24px;
+ max-width: 500px;
+}
+
+.track-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.track-tags span {
+ font-size: 9px;
+ letter-spacing: 2px;
+ padding: 6px 12px;
+ border: 1px solid #4fd1d940;
+ color: var(--purple);
+ text-transform: uppercase;
+ transition: all 0.3s ease;
+}
+
+.track-tags span:hover {
+ border-color: var(--purple);
+ color: var(--purple);
+ box-shadow: 0 0 10px #4fd1d920;
+}
+
+/* Alternate track blocks: even ones shift right */
+.track-block:nth-child(even) .track-content {
+ margin-left: auto;
+ text-align: right;
+}
+
+.track-block:nth-child(even) .track-tags {
+ justify-content: flex-end;
+}
+
+/* ===== PRIZES SECTION ===== */
+#prizes-section {
+ border-top: 2px solid #4fd1d920;
+}
+
+.prizes-layout {
+ max-width: 800px;
+ margin: 0 auto;
+}
+
+.prizes-pool {
+ text-align: center;
+ padding: 50px 20px 40px;
+ margin-bottom: 40px;
+}
+
+.prizes-pool-label {
+ font-size: 10px;
+ letter-spacing: 6px;
+ color: var(--text-dim);
+ margin-bottom: 16px;
+}
+
+.prizes-pool-amount {
+ font-size: clamp(48px, 12vw, 100px);
+ font-weight: bold;
+ letter-spacing: 0.02em;
+ line-height: 1;
+ color: var(--red);
+}
+
+.prizes-pool-sub {
+ font-size: 10px;
+ letter-spacing: 4px;
+ color: var(--cyan);
+ margin-top: 16px;
+ opacity: 0.7;
+}
+
+.prizes-tracks {
+ display: flex;
+ gap: 0;
+ border: 1px solid #4fd1d920;
+}
+
+.prizes-track {
+ flex: 1;
+ padding: 30px;
+}
+
+.prizes-divider {
+ width: 1px;
+ background: #4fd1d920;
+}
+
+.prizes-track-label {
+ font-size: 10px;
+ letter-spacing: 4px;
+ color: var(--cyan);
+ margin-bottom: 24px;
+ opacity: 0.7;
+}
+
+.prizes-track-prizes {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.prize-place {
+ display: flex;
+ align-items: baseline;
+ gap: 16px;
+}
+
+.prize-place-rank {
+ font-size: 11px;
+ letter-spacing: 3px;
+ color: var(--text-dim);
+ min-width: 30px;
+}
+
+.prize-place-amount {
+ font-size: clamp(24px, 4vw, 36px);
+ font-weight: bold;
+ color: var(--red);
+}
+
+.prize-amount {
+ font-weight: bold;
+}
+
+/* ===== TIMELINE SECTION ===== */
+#timeline-section {
+ border-top: 2px solid #4fd1d920;
+}
+
+.timeline {
+ position: relative;
+ max-width: 800px;
+ margin: 0 auto;
+ padding-left: 0;
+}
+
+.timeline::before {
+ content: "";
+ position: absolute;
+ left: 140px;
+ top: 0;
+ bottom: 0;
+ width: 1px;
+ background: #4fd1d920;
+}
+
+.timeline-item {
+ position: relative;
+ display: flex;
+ align-items: baseline;
+ gap: 40px;
+ padding: 30px 0;
+ border-bottom: 1px solid #4fd1d910;
+ opacity: 0;
+ transform: translateY(10px);
+ transition: all 0.6s ease;
+}
+
+.timeline-item.visible {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.timeline-dot {
+ position: absolute;
+ left: 136px;
+ top: 38px;
+ width: 9px;
+ height: 9px;
+ border: 1px solid #4fd1d940;
+ background: #0a1628;
+ transition: all 0.4s ease;
+ z-index: 1;
+}
+
+.timeline-item.visible .timeline-dot {
+ border-color: #4fd1d9cc;
+ box-shadow: 0 0 8px #4fd1d930;
+}
+
+.timeline-item.active .timeline-dot {
+ background: var(--gold);
+ border-color: var(--gold);
+ box-shadow: 0 0 20px #4fd1d960;
+}
+
+.timeline-date {
+ font-size: clamp(20px, 3vw, 32px);
+ font-weight: bold;
+ letter-spacing: 0.06em;
+ color: #4fd1d9b0;
+ min-width: 120px;
+ text-align: right;
+ flex-shrink: 0;
+}
+
+.timeline-item.active .timeline-date {
+ color: var(--gold);
+ text-shadow: 0 0 20px #4fd1d930;
+}
+
+.timeline-event {
+ font-size: clamp(14px, 2vw, 18px);
+ letter-spacing: 3px;
+ padding-left: 30px;
+ color: var(--text);
+}
+
+.timeline-item.active .timeline-event {
+ color: var(--gold);
+}
+
+/* ===== FAQ SECTION ===== */
+#faq-section {
+ border-top: 2px solid #4fd1d920;
+}
+
+.faq-list {
+ max-width: 700px;
+ margin: 0 auto;
+}
+
+.faq-item {
+ border: none;
+ border-bottom: 1px solid #4fd1d918;
+ margin-bottom: 0;
+ overflow: hidden;
+ transition: all 0.3s ease;
+}
+
+.faq-item:first-child {
+ border-top: 1px solid #4fd1d918;
+}
+
+.faq-item:hover {
+ background: #ff174806;
+}
+
+.faq-question {
+ padding: 22px 0;
+ cursor: pointer;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 13px;
+ letter-spacing: 2px;
+ transition: all 0.3s ease;
+ background: none;
+}
+
+.faq-question::before {
+ content: ">";
+ margin-right: 12px;
+ color: var(--cyan);
+ font-size: 14px;
+ opacity: 0.5;
+ transition: all 0.3s ease;
+}
+
+.faq-item:hover .faq-question::before,
+.faq-item.open .faq-question::before {
+ color: var(--cyan);
+ opacity: 1;
+}
+
+.faq-question:hover {
+ background: none;
+ color: #4fd1d9;
+}
+
+.faq-toggle {
+ font-size: 16px;
+ transition: transform 0.3s ease;
+ color: #4fd1d990;
+ flex-shrink: 0;
+}
+
+.faq-item.open .faq-toggle {
+ transform: rotate(45deg);
+ color: #4fd1d9;
+}
+
+.faq-answer {
+ max-height: 0;
+ overflow: hidden;
+ transition:
+ max-height 0.4s ease,
+ padding 0.4s ease;
+ font-size: 12px;
+ line-height: 1.9;
+ color: var(--text);
+ padding: 0 0 0 22px;
+ border-left: 1px solid var(--cyan);
+ margin-left: 8px;
+}
+
+.faq-item.open .faq-answer {
+ max-height: 250px;
+ padding: 0 0 24px 22px;
+}
+
+/* ===== PERKS (WHAT YOU GET) — Bento Grid ===== */
+#perks-section {
+ border-top: 2px solid #4fd1d920;
+ position: relative;
+}
+
+#perks-bg-canvas {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 0;
+}
+
+.perks-bento {
+ display: grid;
+ grid-template-columns: 2fr 1fr 1fr;
+ grid-template-rows: auto auto auto;
+ gap: 3px;
+ max-width: 750px;
+ margin: 0 auto;
+ position: relative;
+ z-index: 1;
+}
+
+@media (max-width: 480px) {
+ .perks-bento {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ max-width: 98vw;
+ width: 100%;
+ align-items: stretch;
+ }
+ .bento-cell {
+ width: 100%;
+ min-width: 0;
+ padding: 20px 12px;
+ box-sizing: border-box;
+ border-radius: 8px;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ }
+ .bento-hero, .bento-wide, .bento-network-row {
+ width: 100%;
+ min-width: 0;
+ border-radius: 8px;
+ grid-column: unset;
+ grid-row: unset;
+ }
+ .centered-text-flex{
+ display:flex;
+ flex-direction:column;
+ justify-content:center;
+ align-items:center;
+ }
+}
+
+
+.bento-cell {
+ border: 1px solid #4fd1d918;
+ padding: 36px 24px;
+ transition:
+ border-color 0.3s ease,
+ background 0.3s ease;
+}
+
+.bento-cell:hover {
+ border-color: #4fd1d940;
+ background: #ff174806;
+}
+
+.bento-hero {
+ grid-row: 1 / 3;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ border-color: #4fd1d925;
+}
+
+.bento-wide {
+ grid-column: 1 / 4;
+}
+
+.bento-network-row {
+ grid-column: 2 / 4;
+ grid-row: 2 / 3;
+ z-index: 2;
+ position: relative;
+}
+
+
+
+.centered-text-flex{
+ display:flex;
+ flex-direction:column;
+ justify-content:center;
+ align-items:center;
+}
+.bento-val {
+ font-size: clamp(28px, 4vw, 44px);
+ font-weight: bold;
+ color: var(--red);
+ line-height: 1.1;
+ margin-bottom: 8px;
+}
+
+.bento-hero .bento-val {
+ font-size: clamp(52px, 10vw, 90px);
+}
+
+.bento-wide .bento-val {
+ font-size: clamp(14px, 2vw, 20px);
+ letter-spacing: 4px;
+ color: var(--cyan);
+}
+
+.bento-label {
+ font-size: 10px;
+ letter-spacing: 3px;
+ color: var(--text-dim);
+}
+
+.bento-sub {
+ font-size: 9px;
+ letter-spacing: 3px;
+ color: var(--cyan);
+ margin-top: 8px;
+ opacity: 0.6;
+}
+
+/* ===== THE TEAM ===== */
+#team-section {
+ border-top: 2px solid #4fd1d920;
+}
+
+.team-counter {
+ text-align: center;
+ margin-bottom: 50px;
+}
+
+.team-number {
+ font-size: clamp(80px, 15vw, 160px);
+ font-weight: bold;
+ letter-spacing: -0.04em;
+ line-height: 1;
+ color: #4fd1d915;
+ display: block;
+}
+
+.team-label {
+ font-size: 10px;
+ letter-spacing: 6px;
+ color: var(--cyan);
+ opacity: 0.7;
+}
+
+.team-marquee-wrap {
+ overflow: hidden;
+ width: 100%;
+ margin-bottom: 12px;
+ -webkit-mask-image: linear-gradient(90deg,
+ transparent,
+ black 10%,
+ black 90%,
+ transparent);
+ mask-image: linear-gradient(90deg,
+ transparent,
+ black 10%,
+ black 90%,
+ transparent);
+}
+
+.team-marquee {
+ display: flex;
+ gap: 12px;
+ width: max-content;
+ animation: marqueeScroll 40s linear infinite;
+}
+
+.team-marquee-wrap.reverse .team-marquee {
+ animation: marqueeScrollReverse 35s linear infinite;
+}
+
+@keyframes marqueeScroll {
+ 0% {
+ transform: translateX(0);
+ }
+
+ 100% {
+ transform: translateX(-50%);
+ }
+}
+
+@keyframes marqueeScrollReverse {
+ 0% {
+ transform: translateX(-50%);
+ }
+
+ 100% {
+ transform: translateX(0);
+ }
+}
+
+.team-card {
+ border: 1px solid #4fd1d915;
+ padding: 20px 16px;
+ text-align: center;
+ transition: border-color 0.3s ease;
+ text-decoration: none;
+ color: inherit;
+}
+
+a.team-card {
+ cursor: pointer;
+}
+
+.team-card:hover {
+ border-color: #4fd1d940;
+}
+
+.team-photo {
+ width: 56px;
+ height: 56px;
+ border-radius: 50%;
+ margin: 0 auto 12px;
+ border: 1px solid #4fd1d930;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 18px;
+ font-weight: bold;
+ color: #4fd1d940;
+ letter-spacing: 1px;
+ overflow: hidden;
+ background: #ff174808;
+}
+
+.team-photo img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ border-radius: 50%;
+}
+
+.team-name {
+ font-size: 11px;
+ letter-spacing: 2px;
+ margin-bottom: 4px;
+ color: var(--text);
+}
+
+.team-role {
+ font-size: 8px;
+ letter-spacing: 3px;
+ color: var(--cyan);
+ opacity: 0.7;
+ margin-bottom: 6px;
+ text-transform: uppercase;
+}
+
+.team-cred {
+ font-size: 8px;
+ letter-spacing: 1px;
+ color: var(--text-dim);
+ line-height: 1.5;
+}
+
+.team-dept {
+ font-size: 7px;
+ letter-spacing: 2px;
+ color: var(--text-dim);
+ margin-top: 4px;
+}
+
+.team-row-label {
+ font-size: 9px;
+ letter-spacing: 4px;
+ color: var(--cyan);
+ opacity: 0.6;
+ margin-bottom: 8px;
+ margin-top: 20px;
+ text-align: left;
+ max-width: 900px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 4px;
+}
+
+.team-note {
+ text-align: center;
+ font-size: 10px;
+ letter-spacing: 4px;
+ color: var(--text-dim);
+ margin-top: 20px;
+}
+
+/* ===== SPONSORS ===== */
+#sponsors-section {
+ border-top: 2px solid #4fd1d920;
+}
+
+.sponsors-tiers {
+ max-width: 800px;
+ margin: 0 auto 40px;
+}
+
+.sponsor-tier {
+ margin-bottom: 40px;
+}
+
+.tier-label {
+ font-size: 10px;
+ letter-spacing: 4px;
+ color: var(--cyan);
+ opacity: 0.7;
+ margin-bottom: 16px;
+ text-align: center;
+}
+
+.sponsor-logos {
+ display: flex;
+ justify-content: center;
+ gap: 20px;
+ flex-wrap: wrap;
+}
+
+.sponsor-slot {
+ border: 1px dashed #4fd1d925;
+ padding: 30px 40px;
+ font-size: 12px;
+ letter-spacing: 3px;
+ color: #4fd1d940;
+ text-align: center;
+ min-width: 200px;
+ transition: border-color 0.3s ease;
+}
+
+.sponsor-slot:hover {
+ border-color: #4fd1d950;
+}
+
+.title-tier .sponsor-slot {
+ padding: 50px 60px;
+ font-size: 14px;
+ min-width: 300px;
+ border-color: var(--gold);
+ color: var(--gold);
+ opacity: 0.5;
+}
+
+.sponsor-slot.small {
+ padding: 20px 24px;
+ min-width: 140px;
+ font-size: 10px;
+}
+
+.sponsors-cta {
+ text-align: center;
+ font-size: 12px;
+ letter-spacing: 3px;
+ color: var(--text-dim);
+}
+
+.sponsors-cta a {
+ color: var(--red);
+ text-decoration: none;
+ border-bottom: 1px solid var(--red);
+ transition: opacity 0.3s;
+}
+
+.sponsors-cta a:hover {
+ opacity: 0.7;
+}
+
+.past-sponsors {
+ margin-top: 60px;
+ padding-top: 40px;
+ border-top: 1px solid #4fd1d915;
+}
+
+.past-sponsors-label {
+ font-size: 10px;
+ letter-spacing: 4px;
+ color: var(--text-dim);
+ text-align: center;
+ margin-bottom: 20px;
+}
+
+.past-sponsors-marquee-wrap {
+ overflow: hidden;
+ width: 100%;
+ -webkit-mask-image: linear-gradient(90deg,
+ transparent,
+ black 10%,
+ black 90%,
+ transparent);
+ mask-image: linear-gradient(90deg,
+ transparent,
+ black 10%,
+ black 90%,
+ transparent);
+}
+
+.past-sponsors-marquee {
+ display: flex;
+ gap: 40px;
+ width: max-content;
+ animation: marqueeScroll 30s linear infinite;
+}
+
+.past-sponsors-marquee span {
+ font-size: 12px;
+ letter-spacing: 4px;
+ color: #4fd1d935;
+ white-space: nowrap;
+ transition: color 0.3s ease;
+}
+
+.past-sponsors-marquee span:hover {
+ color: #4fd1d970;
+}
+
+/* ===== FOOTER ===== */
+#footer-section {
+ position: relative;
+ border-top: 2px solid #4fd1d920;
+ padding: 80px 20px;
+ overflow: hidden;
+}
+
+#footer-section canvas {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 0;
+}
+
+.footer-content {
+ position: relative;
+ z-index: 1;
+ max-width: 700px;
+ margin: 0 auto;
+ text-align: left;
+}
+
+.footer-brand {
+ margin-bottom: 40px;
+ padding-bottom: 30px;
+ border-bottom: 1px solid #4fd1d918;
+}
+
+.footer-logo {
+ font-size: clamp(28px, 5vw, 48px);
+ font-weight: bold;
+ letter-spacing: 0.15em;
+ line-height: 1;
+}
+
+.footer-tagline {
+ font-size: 10px;
+ letter-spacing: 5px;
+ color: var(--cyan);
+ margin-top: 8px;
+ text-transform: uppercase;
+ opacity: 0.7;
+}
+
+.footer-tagline::before {
+ content: "// ";
+ color: var(--cyan);
+ opacity: 0.5;
+}
+
+.footer-links {
+ display: flex;
+ justify-content: flex-start;
+ gap: 24px;
+ flex-wrap: wrap;
+ margin-bottom: 30px;
+}
+
+.footer-links a {
+ color: #4fd1d9b0;
+ text-decoration: none;
+ font-size: 11px;
+ letter-spacing: 3px;
+ text-transform: uppercase;
+ transition: color 0.3s;
+ position: relative;
+}
+
+.footer-links a::before {
+ content: "[";
+ margin-right: 2px;
+ color: #4fd1d980;
+}
+
+.footer-links a::after {
+ content: "]";
+ margin-left: 2px;
+ color: #4fd1d980;
+}
+
+.footer-links a:hover {
+ color: #4fd1d9;
+}
+
+.footer-links a:hover::before,
+.footer-links a:hover::after {
+ color: #4fd1d9cc;
+}
+
+.footer-social {
+ font-size: 11px;
+ letter-spacing: 2px;
+ color: #4fd1d980;
+ margin-bottom: 30px;
+ cursor: pointer;
+}
+
+.footer-social span {
+ transition: color 0.3s;
+}
+
+.footer-social span:hover {
+ color: #4fd1d9;
+ text-shadow: 0 0 10px #4fd1d930;
+}
+
+.footer-copy {
+ font-size: 9px;
+ letter-spacing: 3px;
+ color: #4fd1d970;
+ text-transform: uppercase;
+}
+
+/* ===== FIXED ELEMENTS ===== */
+#register-btn {
+ position: fixed;
+ bottom: 30px;
+ right: 30px;
+ z-index: 1000;
+ background: #0a1628;
+ border: 1px solid #4fd1d9;
+ color: #4fd1d9;
+ font-family: "Geist Pixel", "Courier New", monospace;
+ font-size: 12px;
+ padding: 12px 20px;
+ letter-spacing: 4px;
+ text-transform: uppercase;
+ text-decoration: none;
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+#register-btn::before {
+ content: "> ";
+ color: #4fd1d9b0;
+}
+
+#register-btn:hover {
+ background: #4fd1d9;
+ color: #0a1628;
+ box-shadow: 0 0 40px #4fd1d950;
+}
+
+#register-btn:hover::before {
+ color: #0a162880;
+}
+
+#announcement-bar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ z-index: 999;
+ background: #0a1628;
+ border-bottom: 1px solid #4fd1d930;
+ color: #4fd1d9cc;
+ font-family: "Geist Pixel", "Courier New", monospace;
+ font-size: 11px;
+ padding: 8px 0;
+ text-align: center;
+ letter-spacing: 3px;
+ text-transform: uppercase;
+ opacity: 0;
+ transition: opacity 0.5s ease;
+ pointer-events: none;
+}
+
+#announcement-bar.visible {
+ opacity: 1;
+}
+
+.loadingclass {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100vh;
+ z-index: 9999;
+ display: grid;
+ place-content: center;
+ font-family: "Geist Pixel", "Courier New", monospace;
+ font-size: 14px;
+ letter-spacing: 4px;
+ color: #4fd1d9;
+ background: #0a1628;
+ text-transform: uppercase;
+}
+
+.loadingclass::after {
+ content: "";
+ display: block;
+ width: 40px;
+ height: 1px;
+ background: #4fd1d9;
+ margin: 16px auto 0;
+ animation: subtlePulse 1.5s infinite;
+}
+
+/* ===== MICRO INTERACTIONS ===== */
+.track-block,
+.readout-row,
+.prize-entry {
+ transition:
+ background 0.4s ease,
+ border-color 0.4s ease;
+ will-change: auto;
+}
+
+/* Keep old selectors for sections.js compatibility */
+.info-card,
+.prize-card,
+.track-card {
+ transition:
+ background 0.4s ease,
+ border-color 0.4s ease;
+ will-change: auto;
+}
+
+.glitch-hover {
+ animation: none !important;
+}
+
+.timeline-dot {
+ transition: all 0.4s ease;
+}
+
+/* ===== SCROLL PROGRESS ===== */
+#scroll-progress {
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 3px;
+ background: var(--red);
+ z-index: 10000;
+ transition: width 0.1s linear;
+ pointer-events: none;
+}
+
+/* ===== EASTER EGG FLASH ===== */
+.easter-egg-flash {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ z-index: 10001;
+ font-family: "Geist Pixel", "Courier New", monospace;
+ font-size: clamp(14px, 2.5vw, 20px);
+ letter-spacing: 4px;
+ text-align: center;
+ pointer-events: none;
+ animation: flashIn 2s ease forwards;
+}
+
+@keyframes flashIn {
+ 0% {
+ opacity: 0;
+ transform: translate(-50%, -50%) scale(0.8);
+ }
+
+ 15% {
+ opacity: 1;
+ transform: translate(-50%, -50%) scale(1.05);
+ }
+
+ 85% {
+ opacity: 1;
+ transform: translate(-50%, -50%) scale(1);
+ }
+
+ 100% {
+ opacity: 0;
+ transform: translate(-50%, -50%) scale(1.1);
+ }
+}
+
+/* ===== BOTTOM SECRET MESSAGE ===== */
+#bottom-secret {
+ text-align: center;
+ padding: 40px 20px;
+ font-size: 12px;
+ letter-spacing: 3px;
+ color: var(--purple);
+ opacity: 0;
+ transition: opacity 1s ease;
+}
+
+#bottom-secret.visible {
+ opacity: 1;
+}
+
+/* ===== IDLE MESSAGE ===== */
+.idle-message {
+ position: fixed;
+ bottom: 80px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 999;
+ font-family: "Geist Pixel", "Courier New", monospace;
+ font-size: 12px;
+ letter-spacing: 2px;
+ color: var(--gold);
+ pointer-events: auto;
+ animation: flashIn 5s ease forwards;
+}
+
+.idle-message a {
+ color: var(--red);
+ text-decoration: none;
+ border-bottom: 1px solid var(--red);
+}
+
+/* ===== TRACK TAG FLASH ===== */
+.track-tags span {
+ cursor: pointer;
+}
+
+/* ===== HOVER WARMTH ===== */
+.hover-warmth {
+ transition:
+ box-shadow 0.4s ease,
+ background 0.4s ease;
+}
+
+.hover-warmth:hover {
+ box-shadow:
+ inset 0 0 30px #4fd1d908,
+ 0 0 15px #4fd1d906;
+}
+
+/* ===== TIMELINE LINE DRAW ===== */
+.timeline-line {
+ position: absolute;
+ left: 140px;
+ top: 0;
+ width: 1px;
+ height: 0;
+ background: var(--red);
+ z-index: 1;
+ transition: none;
+}
+
+/* ===== FIREWORKS CANVAS ===== */
+#fireworks-canvas {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 10001;
+ pointer-events: none;
+}
+
+/* ===== TABLET (max 768px) ===== */
+@media (max-width: 768px) {
+ .section-content {
+ padding: 70px 16px;
+ }
+
+ .glitch-text {
+ font-size: clamp(32px, 9vw, 64px);
+ letter-spacing: 0.1em;
+ margin-bottom: 30px;
+ }
+
+ /* About */
+ .about-layout {
+ flex-direction: column;
+ gap: 30px;
+ }
+
+ .about-right {
+ width: 100%;
+ }
+
+ .about-right {
+ display: block;
+ }
+
+ .about-model {
+ width: min(520px, 96vw);
+ height: min(520px, 96vw);
+ margin: 0 auto;
+ }
+
+ .about-left .glitch-text {
+ text-align: center;
+ }
+
+ .about-tagline,
+ .about-desc {
+ text-align: center;
+ }
+
+ .about-cta {
+ display: block;
+ text-align: center;
+ }
+
+ .about-stat-value {
+ font-size: clamp(16px, 4vw, 22px);
+ }
+
+ /* Perks */
+ .perks-bento {
+ grid-template-columns: 1fr 1fr;
+ }
+
+ .bento-hero {
+ grid-column: 1 / -1;
+ grid-row: auto;
+ text-align: center;
+ padding: 30px 16px;
+ }
+
+ .bento-wide {
+ grid-column: 1 / -1;
+ }
+
+ .bento-cell {
+ padding: 24px 16px;
+ }
+
+ .bento-hero .bento-val {
+ font-size: clamp(40px, 12vw, 64px);
+ }
+
+ /* Prizes */
+ .prizes-tracks {
+ flex-direction: column;
+ }
+
+ .prizes-divider {
+ width: 100%;
+ height: 1px;
+ }
+
+ .prizes-track {
+ padding: 24px 20px;
+ }
+
+ .prizes-pool-amount {
+ font-size: clamp(36px, 10vw, 64px);
+ }
+
+ /* Timeline */
+ .timeline::before {
+ left: 0;
+ }
+
+ .timeline-item {
+ flex-direction: column;
+ gap: 4px;
+ padding-left: 20px;
+ }
+
+ .timeline-dot {
+ left: -4px;
+ top: 34px;
+ }
+
+ .timeline-date {
+ text-align: left;
+ min-width: auto;
+ font-size: clamp(16px, 4vw, 24px);
+ }
+
+ .timeline-event {
+ padding-left: 0;
+ font-size: 12px;
+ }
+
+ /* FAQ */
+ .faq-question {
+ font-size: 12px;
+ letter-spacing: 1px;
+ }
+
+ .faq-answer {
+ font-size: 11px;
+ }
+
+ /* Team */
+ .team-card {
+ padding: 14px 10px;
+ min-width: 110px;
+ }
+
+ .team-photo {
+ width: 40px;
+ height: 40px;
+ font-size: 13px;
+ }
+
+ .team-name {
+ font-size: 9px;
+ }
+
+ .team-role {
+ font-size: 7px;
+ }
+
+ .team-counter .team-number {
+ font-size: clamp(60px, 15vw, 100px);
+ }
+
+ .team-row-label {
+ font-size: 8px;
+ letter-spacing: 3px;
+ }
+
+ /* Sponsors */
+ .sponsor-logos {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .sponsor-slot {
+ min-width: 80%;
+ padding: 20px;
+ }
+
+ .title-tier .sponsor-slot {
+ min-width: 90%;
+ padding: 30px;
+ }
+
+ .past-sponsors-marquee span {
+ font-size: 10px;
+ letter-spacing: 3px;
+ }
+
+ /* Footer */
+ .footer-links {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 10px;
+ }
+
+ .footer-logo {
+ font-size: clamp(24px, 6vw, 36px);
+ }
+
+ /* Register button */
+ #register-btn {
+ bottom: 12px;
+ right: 12px;
+ font-size: 9px;
+ padding: 8px 12px;
+ letter-spacing: 3px;
+ }
+
+ /* Scroll hint */
+ #scroll-hint {
+ font-size: 9px;
+ letter-spacing: 3px;
+ bottom: 30px;
+ }
+}
+
+/* ===== SMALL PHONE (max 480px) ===== */
+@media (max-width: 480px) {
+ .section-content {
+ padding: 50px 12px;
+ }
+
+ .glitch-text {
+ font-size: clamp(26px, 10vw, 48px);
+ letter-spacing: 0.08em;
+ margin-bottom: 24px;
+ }
+
+ /* About */
+ .about-desc {
+ font-size: 12px;
+ }
+
+ .about-stat {
+ padding: 16px 10px;
+ }
+
+ .about-stat-value {
+ font-size: 16px;
+ }
+
+ .about-tagline {
+ font-size: 9px;
+ letter-spacing: 3px;
+ }
+
+ /* Perks */
+ .perks-bento {
+ grid-template-columns: 1fr;
+ }
+
+ .bento-hero {
+ grid-column: 1;
+ }
+
+ .bento-wide {
+ grid-column: 1;
+ }
+
+ /* Prizes */
+ .prize-place-amount {
+ font-size: clamp(20px, 5vw, 28px);
+ }
+
+ .prizes-pool-amount {
+ font-size: clamp(32px, 12vw, 48px);
+ }
+
+ /* Team */
+ .team-card {
+ min-width: 90px;
+ padding: 10px 8px;
+ }
+
+ .team-photo {
+ width: 32px;
+ height: 32px;
+ font-size: 11px;
+ }
+
+ .team-name {
+ font-size: 8px;
+ letter-spacing: 1px;
+ }
+
+ .team-role {
+ font-size: 6px;
+ }
+
+ /* Footer */
+ .footer-social {
+ font-size: 10px;
+ }
+
+ .footer-copy {
+ font-size: 8px;
+ }
+}
+
+/* ===== MUSIC COLOR OSCILLATION ===== */
+html.theme-oscillating {
+ transition: filter 0.35s ease;
+}
+
+html.theme-blue {
+ filter: hue-rotate(-108deg);
+}
\ No newline at end of file
diff --git a/hackx/utils.js b/hackx/utils.js
new file mode 100644
index 00000000..91e0c8db
--- /dev/null
+++ b/hackx/utils.js
@@ -0,0 +1,32 @@
+// suggested solution from https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#avoiding_user_agent_detection
+// to detect touch device rather than using user agent
+const isTouchScreenDevice = () => {
+ let hasTouchScreen = false;
+ if ("maxTouchPoints" in navigator) {
+ hasTouchScreen = navigator.maxTouchPoints > 0;
+ } else if ("msMaxTouchPoints" in navigator) {
+ hasTouchScreen = navigator.msMaxTouchPoints > 0;
+ } else {
+ const mQ = window.matchMedia && matchMedia("(pointer:coarse)");
+ if (mQ && mQ.media === "(pointer:coarse)") {
+ hasTouchScreen = !!mQ.matches;
+ } else if ('orientation' in window) {
+ hasTouchScreen = true; // deprecated, but good fallback
+ } else {
+ // Only as a last resort, fall back to user agent sniffing
+ const UA = navigator.userAgent;
+ hasTouchScreen = (
+ /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
+ /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA)
+ );
+ }
+ }
+ return hasTouchScreen;
+}
+// Takes a value in seconds, returns hh:mm:ss:ms
+const createTimeString = (seconds) => {
+ const baseString = new Date(seconds * 1000).toISOString().substring(11, 23);
+ const hhmm = baseString.split(':');
+ const ssms = hhmm[2].split('.');
+ return `${hhmm[0]}h ${hhmm[1]}m ${ssms[0]}s ${ssms[1]}ms`;
+}
\ No newline at end of file