4sp-dv 1.0.50 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/4simpleproblems_v5.html +138 -151
  2. package/README.md +86 -0
  3. package/logged-in/games.html +0 -36
  4. package/logged-in/securly-tester.html +156 -370
  5. package/logged-in/soundboard.html +6 -23
  6. package/logged-in/velium.html +70 -0
  7. package/package.json +1 -1
  8. package/settings.html +0 -15
  9. package/CMTT/airline-manager-tycoon/airplane-images/aa330.png +0 -0
  10. package/CMTT/airline-manager-tycoon/airplane-images/aa340.png +0 -0
  11. package/CMTT/airline-manager-tycoon/airplane-images/aa350.png +0 -0
  12. package/CMTT/airline-manager-tycoon/airplane-images/aa380.png +0 -0
  13. package/CMTT/airline-manager-tycoon/airplane-images/b737.png +0 -0
  14. package/CMTT/airline-manager-tycoon/airplane-images/b747.png +0 -0
  15. package/CMTT/airline-manager-tycoon/airplane-images/b757.png +0 -0
  16. package/CMTT/airline-manager-tycoon/airplane-images/b767.png +0 -0
  17. package/CMTT/airline-manager-tycoon/airplane-images/b777.png +0 -0
  18. package/CMTT/airline-manager-tycoon/airplane-images/b787.png +0 -0
  19. package/CMTT/airline-manager-tycoon/airplane-images/hi.txt +0 -1
  20. package/CMTT/airline-manager-tycoon/index.html +0 -31
  21. package/CMTT/airline-manager-tycoon/script.js +0 -569
  22. package/CMTT/airline-manager-tycoon/style.css +0 -79
  23. package/CMTT/ez-money-1/icon.png +0 -0
  24. package/CMTT/ez-money-1/index.html +0 -1064
  25. package/CMTT/ez-money-1/script.js +0 -3221
  26. package/CMTT/ez-money-1/style.css +0 -381
  27. package/CMTT/ez-money-2/index.html +0 -22
  28. package/CMTT/ez-money-2/script.js +0 -460
  29. package/CMTT/ez-money-2/style.css +0 -103
  30. package/CMTT/ez-money-3/font.otf +0 -0
  31. package/CMTT/ez-money-3/index.html +0 -62
  32. package/CMTT/ez-money-3/script.js +0 -562
  33. package/CMTT/ez-money-3/style.css +0 -253
  34. package/CMTT/slots/index.html +0 -33
  35. package/CMTT/slots/script.js +0 -134
  36. package/CMTT/slots/style.css +0 -54
@@ -6,11 +6,14 @@
6
6
  <title>4SP - VERSION 5 CLIENT</title>
7
7
  <link rel="icon" type="image/png" href="https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo.png">
8
8
 
9
- <base href="https://cdn.jsdelivr.net/npm/4sp-dv@1.0.48/logged-in/">
9
+ <base href="https://cdn.jsdelivr.net/npm/4sp-dv@1.0.44/logged-in/">
10
10
  <script src="https://cdn.tailwindcss.com"></script>
11
11
  <link href="https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap" rel="stylesheet">
12
12
 
13
13
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
14
+
15
+ <script src="https://cdn.jsdelivr.net/npm/fireworks-js@2.x/dist/index.umd.js"></script>
16
+
14
17
  <style>
15
18
  body {
16
19
  background-color: #040404;
@@ -45,6 +48,27 @@
45
48
  z-index: 60;
46
49
  transition: background-color 0.3s ease, border-color 0.3s ease;
47
50
  position: relative;
51
+ overflow: visible;
52
+ }
53
+
54
+ /* --- FIREWORKS CONTAINER --- */
55
+ #fireworks-container {
56
+ position: absolute;
57
+ top: 0;
58
+ left: 0;
59
+ width: 100%;
60
+ height: 100%;
61
+ pointer-events: none; /* Let clicks pass through */
62
+ z-index: 1; /* Sit above background */
63
+ opacity: 0;
64
+ transition: opacity 0.5s ease;
65
+ overflow: hidden;
66
+ }
67
+
68
+ /* Ensure navbar content sits ABOVE the fireworks */
69
+ #navbar-container > *:not(#fireworks-container) {
70
+ position: relative;
71
+ z-index: 10;
48
72
  }
49
73
 
50
74
  /* --- FIXED OVERLAY LOGIC --- */
@@ -171,15 +195,15 @@
171
195
  z-index: 50;
172
196
  }
173
197
 
174
- /* --- DISABLE ANIMATIONS FOR AUTH BTN --- */
175
198
  #auth-btn, #auth-btn:hover, #auth-btn:active {
176
199
  transform: none !important;
177
200
  transition: none !important;
178
201
  background-color: transparent !important;
179
- z-index: auto !important;
202
+ z-index: 65 !important;
203
+ cursor: pointer !important;
180
204
  }
181
205
 
182
- /* Auth Menu & Settings */
206
+ /* --- Auth Menu & Settings (Updated for dynamic theming) --- */
183
207
  .auth-menu {
184
208
  position: absolute;
185
209
  right: 0;
@@ -192,7 +216,7 @@
192
216
  display: none;
193
217
  flex-direction: column;
194
218
  gap: 0.5rem;
195
- z-index: 50;
219
+ z-index: 70;
196
220
  box-shadow: 0 10px 30px rgba(0,0,0,0.6);
197
221
  transform-origin: top right;
198
222
  }
@@ -213,9 +237,10 @@
213
237
  align-items: center;
214
238
  gap: 0.75rem;
215
239
  padding: 0.75rem 1rem;
216
- color: var(--menu-text, #d1d5db);
217
- background: #0a0a0a;
218
- border: 1px solid #333;
240
+ /* UPDATED: Uses variables for dynamic theme support */
241
+ color: var(--menu-item-text, #d1d5db);
242
+ background: var(--menu-item-bg, #0a0a0a);
243
+ border: 1px solid var(--menu-item-border, #333);
219
244
  border-radius: 1rem;
220
245
  text-decoration: none;
221
246
  font-size: 0.9rem;
@@ -225,9 +250,10 @@
225
250
  }
226
251
 
227
252
  .auth-menu-item:hover {
228
- background-color: #000;
229
- border-color: #fff;
230
- color: #fff;
253
+ /* UPDATED: Uses variables for dynamic theme support */
254
+ background-color: var(--menu-item-hover-bg, #000);
255
+ border-color: var(--menu-item-hover-border, #fff);
256
+ color: var(--menu-item-hover-text, #fff);
231
257
  transform: translateY(-2px) scale(1.02);
232
258
  box-shadow: 0 5px 15px rgba(255,255,255,0.05);
233
259
  }
@@ -236,21 +262,6 @@
236
262
  transform: translateY(0) scale(0.98);
237
263
  }
238
264
 
239
- .auth-menu-item i, .nav-tab i, .settings-tab i {
240
- display: inline-flex;
241
- align-items: center;
242
- justify-content: center;
243
- width: 1.1em;
244
- height: 1.1em;
245
- line-height: 1;
246
- position: relative;
247
- top: 1px;
248
- flex-shrink: 0;
249
- margin: 0;
250
- }
251
-
252
-
253
-
254
265
  .auth-header {
255
266
  padding: 0.5rem 1rem;
256
267
  border-bottom: 1px solid var(--menu-divider, #333);
@@ -320,13 +331,13 @@
320
331
  }
321
332
 
322
333
  .settings-box {
323
- border: 1px solid #333; border-radius: 1.5rem;
334
+ border: 1px solid #333; border-radius: 1rem;
324
335
  background-color: #000000; padding: 1.5rem; margin-bottom: 1.5rem;
325
336
  }
326
337
 
327
338
  .input-text-style, .input-select-style {
328
339
  width: 100%; padding: 0.75rem; border: 1px solid #252525;
329
- background-color: #111111; border-radius: 1rem; color: #c0c0c0; transition: all 0.2s;
340
+ background-color: #111111; border-radius: 0.5rem; color: #c0c0c0; transition: all 0.2s;
330
341
  }
331
342
  .input-text-style:focus, .input-select-style:focus {
332
343
  border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5);
@@ -334,24 +345,13 @@
334
345
 
335
346
  .input-key-style {
336
347
  width: 4rem; padding: 0.75rem; border: 1px solid #252525;
337
- background-color: #111111; border-radius: 1rem; color: #c0c0c0;
348
+ background-color: #111111; border-radius: 0.5rem; color: #c0c0c0;
338
349
  transition: all 0.2s; font-size: 1.1rem; text-align: center;
339
350
  font-weight: 500; text-transform: uppercase; caret-color: transparent;
340
351
  }
341
352
  .input-key-style:focus {
342
353
  border-color: #505050; outline: none; box-shadow: 0 0 0 2px rgba(80, 80, 80, 0.5);
343
354
  }
344
-
345
- /* Preference Toggles */
346
- .icon-btn.off {
347
- border-color: #ef4444;
348
- color: #ef4444;
349
- background-color: rgba(239, 68, 68, 0.05);
350
- }
351
- .icon-btn.off:hover {
352
- background-color: rgba(239, 68, 68, 0.1);
353
- border-color: #f87171;
354
- }
355
355
  .input-key-style::placeholder { font-size: 1rem; text-transform: none; }
356
356
 
357
357
  .general-message-area { min-height: 20px; margin-top: 1rem; font-weight: 400; }
@@ -406,21 +406,8 @@
406
406
  }
407
407
  .shake-anim { animation: shake 0.4s cubic-bezier(.36,.07,.19,.97) both; }
408
408
 
409
- /* Animation Control */
410
- body.no-animations *,
411
- body.no-animations *:hover,
412
- body.no-animations *:active,
413
- body.no-animations *:focus {
414
- transition: none !important;
415
- animation: none !important;
416
- transform: none !important;
417
- box-shadow: none !important;
418
- }
419
-
420
- body.no-animations .auth-menu-item .fa-gear,
421
- body.no-animations .nav-tab .fa-gear {
422
- transition: none !important;
423
- transform: none !important;
409
+ body.no-animations * {
410
+ transition: none !important; animation: none !important; transform: none !important;
424
411
  }
425
412
 
426
413
  /* Bubbly Spring Transition */
@@ -587,6 +574,8 @@
587
574
  </div>
588
575
 
589
576
  <div id="navbar-container">
577
+ <div id="fireworks-container"></div>
578
+
590
579
  <img src="https://cdn.jsdelivr.net/npm/4sp-asset-library@latest/logo.png" id="navbar-logo" class="navbar-logo" alt="Logo">
591
580
 
592
581
  <div class="tab-wrapper">
@@ -643,29 +632,13 @@
643
632
  <h3 class="text-3xl font-bold text-white mb-6">General Settings</h3>
644
633
 
645
634
  <div class="settings-box">
646
- <h3 class="text-xl font-bold text-white mb-2">Account Details & Preferences</h3>
647
-
635
+ <h3 class="text-xl font-bold text-white mb-2">Account Username</h3>
648
636
  <label class="block text-gray-400 text-sm mb-2 font-light">New Username</label>
649
- <div class="flex gap-2 mb-6">
637
+ <div class="flex gap-2">
650
638
  <input type="text" id="settings-username-input" class="input-text-style" placeholder="Enter username">
651
639
  <button id="save-username-btn" class="btn-toolbar-style btn-primary-override">Save</button>
652
640
  </div>
653
641
  <p id="username-msg" class="general-message-area text-sm mt-2"></p>
654
-
655
- <div class="flex gap-8 items-center pt-4 border-t border-[#1a1a1a]">
656
- <div class="flex flex-col items-center gap-2">
657
- <button id="toggle-animations-btn" class="icon-btn" title="Toggle Navbar Animations">
658
- <i class="fa-solid fa-wand-magic-sparkles"></i>
659
- </button>
660
- <span class="text-xs text-gray-500">Animations</span>
661
- </div>
662
- <div class="flex flex-col items-center gap-2">
663
- <button id="toggle-sounds-btn" class="icon-btn" title="Toggle UI Sounds">
664
- <i class="fa-solid fa-volume-high"></i>
665
- </button>
666
- <span class="text-xs text-gray-500">Sounds</span>
667
- </div>
668
- </div>
669
642
  </div>
670
643
 
671
644
  <h3 class="text-xl font-bold text-white mb-2 mt-6">Organization</h3>
@@ -718,8 +691,7 @@
718
691
 
719
692
  <label class="block text-gray-400 text-xs mb-2 font-light">Background Color</label>
720
693
  <div class="flex flex-wrap gap-2 mb-6" id="pfp-color-grid">
721
- <!-- Colors generated by JS -->
722
- </div>
694
+ </div>
723
695
 
724
696
  <button id="save-letter-pfp-btn" class="btn-toolbar-style btn-primary-override w-full justify-center">Set Letter Avatar</button>
725
697
  </div>
@@ -740,8 +712,7 @@
740
712
 
741
713
  <h3 class="text-xl font-bold text-white mb-2">Navigation Bar Theme</h3>
742
714
  <div class="settings-box p-4">
743
- <div id="theme-picker-container">
744
- </div>
715
+ <div id="theme-picker-container"></div>
745
716
  </div>
746
717
  </div>
747
718
 
@@ -880,7 +851,7 @@
880
851
  const displayUsername = document.getElementById('display-username');
881
852
  const displayEmail = document.getElementById('display-email');
882
853
 
883
- const BASE_URL = 'https://cdn.jsdelivr.net/npm/4sp-dv@1.0.48/logged-in/';
854
+ const BASE_URL = 'https://cdn.jsdelivr.net/npm/4sp-dv@1.0.44/logged-in/';
884
855
 
885
856
  // Preload Logos
886
857
  const preloadImgs = [
@@ -894,8 +865,10 @@
894
865
  const USER_DATA_KEY = 'local_user_data';
895
866
  const LAST_PAGE_KEY = 'local_last_page';
896
867
  const OWNER_EMAIL = "4simpleproblems@gmail.com"; // For admin checks
868
+ const FIREWORKS_SETTINGS_KEY = 'fireworks_settings';
897
869
 
898
- const PAGE_DATA = {
870
+ // RENAMED TO AVOID CONFLICTS
871
+ const CLIENT_PAGE_DATA = {
899
872
  "dashboard": { "name": "Dashboard", "icon": "fa-solid fa-house-user", "url": "dashboard.html" },
900
873
  "soundboard": { "name": "Soundboard", "icon": "fa-solid fa-volume-up", "url": "soundboard.html" },
901
874
  "notes": { "name": "Notes", "icon": "fa-solid fa-sticky-note", "url": "notes.html" },
@@ -905,12 +878,34 @@
905
878
  "dictionary": { "name": "Dictionary", "icon": "fa-solid fa-book", "url": "dictionary.html" },
906
879
  "messenger-v2": { "name": "Messenger", "icon": "fa-solid fa-comments", "url": "messenger-v2.html" },
907
880
  "games": { "name": "GAMES", "icon": "fa-solid fa-gamepad", "url": "games.html" },
881
+ "velium": { "name": "Velium", "icon": "fa-solid fa-music", "url": "velium.html" },
908
882
  "settings": { "name": "Settings", "icon": "fa-solid fa-gear", "url": "settings.html" }
909
883
  };
910
884
 
911
885
  let currentUser = null;
912
886
  let userDataUnsubscribe = null;
913
887
 
888
+ // --- FIREWORKS ENGINE INITIALIZATION ---
889
+ const fwContainer = document.getElementById('fireworks-container');
890
+
891
+ // HARDCODED SETTINGS AS REQUESTED
892
+ const fireworks = new Fireworks.default(fwContainer, {
893
+ autoresize: true,
894
+ opacity: 1.0, // Hardcoded
895
+ acceleration: 1.05,
896
+ friction: 0.97,
897
+ gravity: 1.5,
898
+ particles: 50, // Hardcoded
899
+ traceLength: 3,
900
+ traceSpeed: 10,
901
+ explosion: 5,
902
+ intensity: 5, // Hardcoded
903
+ flickering: 50,
904
+ lineStyle: 'round',
905
+ rocketsPoint: { min: 50, max: 50 }
906
+ });
907
+
908
+
914
909
  // --- ADMIN KEYBINDS LOGIC (Updated to Match admin_keybinds.js exactly) ---
915
910
  function initAdminKeybinds(db, auth, user) {
916
911
  console.log("[Admin Keybinds] Initializing for", user.uid);
@@ -1171,7 +1166,7 @@
1171
1166
 
1172
1167
  let currentPath = activePageUrl.replace(BASE_URL, '');
1173
1168
 
1174
- Object.entries(PAGE_DATA).forEach(([key, page]) => {
1169
+ Object.entries(CLIENT_PAGE_DATA).forEach(([key, page]) => {
1175
1170
  const isAuth = page.url === currentPath;
1176
1171
  const tab = document.createElement('a');
1177
1172
  tab.className = `nav-tab ${isAuth ? 'active' : ''}`;
@@ -1247,7 +1242,7 @@
1247
1242
  }, 50);
1248
1243
  }
1249
1244
 
1250
- // Auth Menu
1245
+ // Auth Menu (Wait for DOMContentLoaded equivalent in module)
1251
1246
  if (authBtn) {
1252
1247
  authBtn.addEventListener('click', (e) => {
1253
1248
  e.stopPropagation();
@@ -1370,9 +1365,6 @@
1370
1365
  }
1371
1366
 
1372
1367
  authBtn.innerHTML = pfpHtml;
1373
- authBtn.style.padding = '0'; // Remove padding to let avatar fill
1374
- authBtn.style.overflow = 'hidden'; // Ensure roundness
1375
- authBtn.style.border = '1px solid #4b5563'; // Maintain border
1376
1368
  }
1377
1369
 
1378
1370
  // --- Auto-Login Logic ---
@@ -1495,7 +1487,7 @@
1495
1487
 
1496
1488
  // Priority: Last Page > > Default
1497
1489
  if (lastPage) {
1498
- const isValid = Object.values(PAGE_DATA).some(p => p.url === lastPage);
1490
+ const isValid = Object.values(CLIENT_PAGE_DATA).some(p => p.url === lastPage);
1499
1491
  if (isValid) startPage = lastPage;
1500
1492
  }
1501
1493
 
@@ -1551,7 +1543,7 @@
1551
1543
  if (loader && loaderTitle && loaderBar) {
1552
1544
  // Determine Title
1553
1545
  let pageTitle = "Loading...";
1554
- const pageEntry = Object.values(PAGE_DATA).find(p => p.url === cleanPageName || p.url.includes(lookupName));
1546
+ const pageEntry = Object.values(CLIENT_PAGE_DATA).find(p => p.url === cleanPageName || p.url.includes(lookupName));
1555
1547
  if (pageEntry) pageTitle = pageEntry.name;
1556
1548
 
1557
1549
  loaderTitle.textContent = pageTitle;
@@ -2156,8 +2148,42 @@
2156
2148
  if (!res.ok) return;
2157
2149
  let themes = await res.json();
2158
2150
 
2151
+ // --- INJECT CUSTOM "THE NEW YEAR" THEME & REMOVE ROYAL ---
2152
+ // 1. Filter out Royal
2153
+ themes = themes.filter(t => t.name !== 'Royal');
2154
+
2155
+ // 2. Inject The New Year (Deep Blue)
2156
+ const newYearTheme = {
2157
+ "name": "The New Year",
2158
+ "navbar-bg": "#020617", // Very deep blue (Slate-950)
2159
+ "navbar-border": "#1e293b",
2160
+ "navbar-text": "#e2e8f0",
2161
+ "tab-text": "#94a3b8",
2162
+ "tab-hover-text": "#ffffff",
2163
+ "tab-hover-bg": "rgba(255, 255, 255, 0.1)",
2164
+ "tab-active-text": "#fcd34d", // Gold accent for festive feel
2165
+ "tab-active-bg": "rgba(252, 211, 77, 0.15)",
2166
+ "tab-active-border": "#fcd34d",
2167
+ "accent-color": "#fcd34d",
2168
+ "logo-src": "https://cdn.jsdelivr.net/npm/4sp-asset-library@latest/logo.png",
2169
+
2170
+ // --- UPDATED: AUTH MENU SPECIFIC THEME COLORS ---
2171
+ "menu-bg": "#020617",
2172
+ "menu-border": "#fcd34d", // Gold border for menu
2173
+ "menu-divider": "#1e293b",
2174
+ "menu-username-text": "#fcd34d", // Gold Username
2175
+ "menu-email-text": "#94a3b8",
2176
+ "menu-item-bg": "#0f172a", // Dark Slate for items
2177
+ "menu-item-text": "#cbd5e1",
2178
+ "menu-item-hover-bg": "rgba(252, 211, 77, 0.1)", // Gold tint on hover
2179
+ "menu-item-hover-text": "#fcd34d"
2180
+ };
2181
+
2182
+ themes.push(newYearTheme);
2183
+ // --------------------------------------------------------
2184
+
2159
2185
  // --- Sorting Logic from settings.js ---
2160
- const orderedThemeNames = ['Dark', 'Light', 'Christmas'];
2186
+ const orderedThemeNames = ['Dark', 'Light', 'Christmas', 'The New Year']; // Prioritize New Year
2161
2187
  const sortedThemes = [];
2162
2188
 
2163
2189
  orderedThemeNames.forEach(name => {
@@ -2222,22 +2248,33 @@
2222
2248
  function applyTheme(theme) {
2223
2249
  const root = document.documentElement;
2224
2250
 
2251
+ // --- FIREWORKS LOGIC ---
2252
+ if (theme.name === 'The New Year') {
2253
+ document.getElementById('fireworks-container').style.opacity = '1';
2254
+ fireworks.start();
2255
+ } else {
2256
+ document.getElementById('fireworks-container').style.opacity = '0';
2257
+ fireworks.stop();
2258
+ }
2259
+ // -----------------------
2260
+
2225
2261
  // --- Logo Path Modification ---
2226
2262
  let logoSrc;
2227
2263
  const isLightTheme = lightThemeNames.includes(theme.name);
2228
2264
 
2229
2265
  if (isLightTheme) {
2230
2266
  logoSrc = 'https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo-dark.png';
2231
- root.style.setProperty('--menu-username-text', '#000000');
2232
- root.style.setProperty('--menu-email-text', '#444444');
2267
+ // Default light theme variables if not specified in theme
2268
+ if(!theme['menu-username-text']) root.style.setProperty('--menu-username-text', '#000000');
2269
+ if(!theme['menu-email-text']) root.style.setProperty('--menu-email-text', '#444444');
2233
2270
  } else if (theme.name === 'Christmas') {
2234
2271
  logoSrc = 'https://cdn.jsdelivr.net/npm/4sp-dv@latest/images/logo-christmas.png';
2235
- root.style.setProperty('--menu-username-text', 'white');
2236
- root.style.setProperty('--menu-email-text', '#9ca3af');
2272
+ if(!theme['menu-username-text']) root.style.setProperty('--menu-username-text', 'white');
2273
+ if(!theme['menu-email-text']) root.style.setProperty('--menu-email-text', '#9ca3af');
2237
2274
  } else {
2238
2275
  logoSrc = 'https://cdn.jsdelivr.net/npm/4sp-asset-library@latest/logo.png';
2239
- root.style.setProperty('--menu-username-text', 'white');
2240
- root.style.setProperty('--menu-email-text', '#9ca3af');
2276
+ if(!theme['menu-username-text']) root.style.setProperty('--menu-username-text', 'white');
2277
+ if(!theme['menu-email-text']) root.style.setProperty('--menu-email-text', '#9ca3af');
2241
2278
  }
2242
2279
 
2243
2280
  // Apply CSS Variables from theme object (overrides defaults if present)
@@ -2286,7 +2323,8 @@
2286
2323
  localStorage.setItem('user-navbar-theme', JSON.stringify(theme));
2287
2324
 
2288
2325
  // Apply Glide Button Color Sync
2289
- root.style.setProperty('--glide-btn-color', 'var(--tab-text)');
2326
+ const glideColor = theme['tab-active-text'] || theme['accent-color'] || '#ffffff';
2327
+ root.style.setProperty('--glide-btn-color', glideColor);
2290
2328
 
2291
2329
  // Also update user doc if logged in
2292
2330
  if (currentUser) {
@@ -2550,41 +2588,6 @@
2550
2588
 
2551
2589
  loadThemes();
2552
2590
  loadPanicKeys();
2553
-
2554
- // --- App Preference Toggles Init ---
2555
- const animBtn = document.getElementById('toggle-animations-btn');
2556
- const soundBtn = document.getElementById('toggle-sounds-btn');
2557
-
2558
- const updateToggleUI = () => {
2559
- const isEnabled = window.areAnimationsEnabled;
2560
- animBtn.classList.toggle('off', !isEnabled);
2561
- animBtn.innerHTML = isEnabled ? '<i class="fa-solid fa-wand-magic-sparkles"></i>' : '<i class="fa-solid fa-wand-magic"></i>';
2562
-
2563
- // Apply to body
2564
- if (isEnabled) document.body.classList.remove('no-animations');
2565
- else document.body.classList.add('no-animations');
2566
-
2567
- soundBtn.classList.toggle('off', window.isMuted);
2568
- soundBtn.innerHTML = window.isMuted ? '<i class="fa-solid fa-volume-xmark"></i>' : '<i class="fa-solid fa-volume-high"></i>';
2569
- };
2570
-
2571
- if (animBtn) {
2572
- animBtn.onclick = () => {
2573
- window.areAnimationsEnabled = !window.areAnimationsEnabled;
2574
- localStorage.setItem('app_animations_enabled', window.areAnimationsEnabled);
2575
- updateToggleUI();
2576
- };
2577
- }
2578
-
2579
- if (soundBtn) {
2580
- soundBtn.onclick = () => {
2581
- window.isMuted = !window.isMuted;
2582
- localStorage.setItem('app_is_muted', window.isMuted);
2583
- updateToggleUI();
2584
- };
2585
- }
2586
-
2587
- updateToggleUI();
2588
2591
  }
2589
2592
 
2590
2593
  checkAutoLogin();
@@ -2596,26 +2599,14 @@
2596
2599
  <script>
2597
2600
  // --- Sound & Notification Logic ---
2598
2601
  const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
2599
-
2600
- // Sync with global state
2601
- Object.defineProperty(window, 'isMuted', {
2602
- get: () => localStorage.getItem('app_is_muted') === 'true',
2603
- set: (v) => localStorage.setItem('app_is_muted', v)
2604
- });
2605
-
2606
- Object.defineProperty(window, 'areAnimationsEnabled', {
2607
- get: () => localStorage.getItem('app_animations_enabled') !== 'false',
2608
- set: (v) => localStorage.setItem('app_animations_enabled', v)
2609
- });
2610
-
2611
- // Initial Class Set
2612
- if (!window.areAnimationsEnabled) document.body.classList.add('no-animations');
2602
+ let isMuted = false;
2603
+ let areAnimationsEnabled = true;
2613
2604
 
2614
2605
  // EXPOSE PlayTypeSound GLOBALLY
2615
2606
  // Debounce to prevent rapid-fire stuttering if called too fast
2616
2607
  let typeSoundTimeout = null;
2617
2608
  window.playTypeSound = function() {
2618
- if (window.isMuted) return;
2609
+ if (isMuted) return;
2619
2610
  if (audioCtx.state === 'suspended') audioCtx.resume();
2620
2611
 
2621
2612
  // Small debounce
@@ -2656,7 +2647,7 @@
2656
2647
  };
2657
2648
 
2658
2649
  function playClickSound() {
2659
- if (window.isMuted) return;
2650
+ if (isMuted) return;
2660
2651
  if (audioCtx.state === 'suspended') audioCtx.resume();
2661
2652
 
2662
2653
  const osc = audioCtx.createOscillator();
@@ -2671,12 +2662,8 @@
2671
2662
  osc.stop(audioCtx.currentTime + 0.015);
2672
2663
  }
2673
2664
 
2674
- // --- App Preferences State ---
2675
- window.isMuted = localStorage.getItem('app_is_muted') === 'true';
2676
- window.areAnimationsEnabled = localStorage.getItem('app_animations_enabled') !== 'false'; // Default true
2677
-
2678
2665
  window.playMechClick = function(isReverse = false) {
2679
- if (window.isMuted || !window.areAnimationsEnabled) return;
2666
+ if (isMuted) return;
2680
2667
  if (audioCtx.state === 'suspended') audioCtx.resume();
2681
2668
  const now = audioCtx.currentTime;
2682
2669
 
@@ -2717,7 +2704,7 @@
2717
2704
  osc.stop(now + 0.02);
2718
2705
  };
2719
2706
 
2720
-
2707
+ // Removed Gear Animation Logic
2721
2708
 
2722
2709
  const notificationContainer = document.getElementById('notification-container');
2723
2710
  function showNotification(message, iconClass = 'fa-solid fa-info-circle', type = 'info') {
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ <div align="center">
2
+ <img src="https://raw.githubusercontent.com/4simpleproblems-v5/4simpleproblems-v5.github.io/main/images/logo.png" width="120" />
3
+
4
+ <h1 style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; font-weight: 400; color: #888; margin-bottom: 0;">
5
+ The platform for everyone. Even you.
6
+ </h1>
7
+ <h1 style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; font-weight: 800; font-size: 3rem; margin-top: 0; color: #fff;">
8
+ The 4SP Organization.
9
+ </h1>
10
+
11
+ <p style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; font-size: 1.2rem; color: #9ca3af; max-width: 600px;">
12
+ Official organizational home for <strong>4simpleproblems</strong>. Version 5 DV is built for unblockable access, full local security, and zero dependencies.
13
+ </p>
14
+
15
+ <div style="margin: 20px 0;">
16
+ <a href="https://4sp-organization.github.io/connection.html" style="text-decoration: none;">
17
+ <span style="background-color: rgba(147, 51, 234, 0.1); color: #c084fc; border: 1px solid rgba(192, 132, 252, 0.5); padding: 12px 24px; border-radius: 12px; font-family: sans-serif; font-weight: 500; margin-right: 10px;">
18
+ Connect to 4SP →
19
+ </span>
20
+ </a>
21
+ <a href="https://4sp-organization.github.io/create_link.html" style="text-decoration: none;">
22
+ <span style="background-color: rgba(249, 115, 22, 0.1); color: #fb923c; border: 1px solid rgba(253, 186, 116, 0.5); padding: 12px 24px; border-radius: 12px; font-family: sans-serif; font-weight: 500;">
23
+ Create a Link →
24
+ </span>
25
+ </a>
26
+ </div>
27
+
28
+ <div style="margin-top: 20px;">
29
+ <a href="https://discord.gg/A798ZZUgca"><img src="https://img.shields.io/badge/Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" /></a>
30
+ <a href="https://linktr.ee/4simpleproblems"><img src="https://img.shields.io/badge/Linktree-39E09B?style=for-the-badge&logo=linktree&logoColor=white" /></a>
31
+ </div>
32
+ </div>
33
+
34
+ <hr style="border: 1px solid #1a1a1a; margin: 40px 0;" />
35
+
36
+ <table style="width: 100%; border-collapse: collapse; border: none; font-family: sans-serif;">
37
+ <tr>
38
+ <td style="width: 33%; padding: 10px; border: none;">
39
+ <div style="background-color: #0d0d0d; border: 1px solid #1a1a1a; border-radius: 12px; padding: 20px; min-height: 150px;">
40
+ <h3 style="color: #c084fc; margin-top: 0;">Creation</h3>
41
+ <p style="color: #9ca3af; font-size: 14px;">Founded March 13, 2025. Started as a basic student soundboard and utility tool.</p>
42
+ </div>
43
+ </td>
44
+ <td style="width: 33%; padding: 10px; border: none;">
45
+ <div style="background-color: #0d0d0d; border: 1px solid #1a1a1a; border-radius: 12px; padding: 20px; min-height: 150px;">
46
+ <h3 style="color: #3b82f6; margin-top: 0;">The Shift (V4)</h3>
47
+ <p style="color: #9ca3af; font-size: 14px;">Introduced dashboard layouts, Tab Disguising, and the famous Panic Key system.</p>
48
+ </div>
49
+ </td>
50
+ <td style="width: 33%; padding: 10px; border: none;">
51
+ <div style="background-color: #0d0d0d; border: 1px solid #1a1a1a; border-radius: 12px; padding: 20px; min-height: 150px;">
52
+ <h3 style="color: #22c55e; margin-top: 0;">Rebuild (V5)</h3>
53
+ <p style="color: #9ca3af; font-size: 14px;">A complete rewrite focusing on security, 1,600+ games, and student utility.</p>
54
+ </div>
55
+ </td>
56
+ </tr>
57
+ </table>
58
+
59
+ <br />
60
+
61
+ <div style="background-color: #0d0d0d; border: 1px solid #1a1a1a; border-radius: 12px; padding: 30px; font-family: sans-serif;">
62
+
63
+ <p style="color: #c0c0c0;">4SP is a student-made web project built for bored school days. It mixes utilities, games, and tools that feel fast and local instead of corporate.</p>
64
+
65
+ <div align="center" style="margin: 20px 0;">
66
+ <img src="https://img.shields.io/badge/HTML5-E34F26?style=flat-square&logo=html5&logoColor=white" />
67
+ <img src="https://img.shields.io/badge/CSS3-1572B6?style=flat-square&logo=css3&logoColor=white" />
68
+ <img src="https://img.shields.io/badge/JavaScript-F7DF1E?style=flat-square&logo=javascript&logoColor=black" />
69
+ <img src="https://img.shields.io/badge/Firebase-FFCA28?style=flat-square&logo=firebase&logoColor=black" />
70
+ </div>
71
+
72
+ <h3 style="color: #fff; border-left: 3px solid #333; padding-left: 10px;">Deployment</h3>
73
+ <p style="color: #9ca3af;">Deploy your own instance of 4SP v5 instantly:</p>
74
+
75
+ <div align="center">
76
+ <a href="https://vercel.com/new/import?framework=other&s=https%3A%2F%2Fgithub.com%2F4simpleproblems-v5%2F4simpleproblems-v5.github.io"><img src="https://img.shields.io/badge/Deploy_to_Vercel-000000?style=for-the-badge&logo=vercel&logoColor=white" /></a>
77
+ <a href="https://app.netlify.com/start/deploy?repository=https://github.com/4simpleproblems-v5/4simpleproblems-v5.github.io"><img src="https://img.shields.io/badge/Deploy_to_Netlify-00C7B7?style=for-the-badge&logo=netlify&logoColor=white" /></a>
78
+ </div>
79
+ </div>
80
+
81
+ <br />
82
+
83
+ <div align="center" style="font-family: sans-serif; color: #606060; font-size: 12px;">
84
+ Developed and Maintained by the 4SP Organization <br />
85
+ &copy; 2025 4SP Organization. Built using modern web standards.
86
+ </div>
@@ -960,42 +960,6 @@
960
960
  zoneFrame.setAttribute('sandbox', sandboxRules);
961
961
  zoneFrame.setAttribute('allow', 'fullscreen; pointer-lock; autoplay; clipboard-write');
962
962
 
963
- // --- SM64 SPECIAL HANDLING (Timeout & Retry) ---
964
- if (game.id === 'other-sm64') {
965
- let attempts = 0;
966
- const tryLoadSM64 = () => {
967
- attempts++;
968
- let success = false;
969
-
970
- const loadHandler = () => {
971
- success = true;
972
- zoneViewer.style.display = "flex";
973
- zoneViewer.classList.remove('animate-fade-out');
974
- zoneViewer.classList.add('active', 'animate-fade-in');
975
- };
976
-
977
- zoneFrame.onload = loadHandler;
978
- // Add timestamp to force reload and bypass cache
979
- zoneFrame.src = `${game.url}?t=${Date.now()}`;
980
-
981
- setTimeout(() => {
982
- if (!success) {
983
- zoneFrame.onload = null; // Clear handler
984
- if (attempts < 2) {
985
- console.log("SM64: Load timed out (5s). Retrying...");
986
- tryLoadSM64();
987
- } else {
988
- console.log("SM64: Failed to load after retry.");
989
- show404("The game failed to load after multiple attempts.");
990
- }
991
- }
992
- }, 5000);
993
- };
994
-
995
- tryLoadSM64();
996
- return;
997
- }
998
-
999
963
  // --- REVISED LOGIC FOR LOADING GAMES ---
1000
964
  const isStandardURLGame = game.category === 'StrongdogXP' || game.category === 'Others' || game.category === 'GN-Math';
1001
965