1/** 2 * Secret KitTV window â triple-click the taskbar clock, or hold the Start logo ~3s. 3 */ 4(function (global) { 5 'use strict'; 6 7 var AUX_ID = 'kittv'; 8 var KITTV_URL = 'https://wowee.neocities.org/kittv/kittv'; 9 var CONTENT_W = 640; 10 var CONTENT_H = 480; 11 var TITLEBAR_PX = 30; 12 var HOLD_MS = 3000; 13 var TRIPLE_CLICK_MS = 600; 14 15 var holdTimer = null; 16 var holdTriggered = false; 17 var clockClickCount = 0; 18 var clockClickTimer = null; 19 20 function qs(sel) { 21 return document.querySelector(sel); 22 } 23 24 function isCitrusDesktop() { 25 return document.body && document.body.classList.contains('page-citrusos'); 26 } 27 28 function getUiScale() { 29 try { 30 var raw = getComputedStyle(document.documentElement).getPropertyValue('--citrusos-ui-scale'); 31 var scale = parseFloat(raw); 32 return scale > 0 ? scale : 1; 33 } catch (e) { 34 return 1; 35 } 36 } 37 38 function getShellSize() { 39 var titlebarH = Math.round(TITLEBAR_PX * getUiScale()); 40 return { 41 w: CONTENT_W, 42 h: CONTENT_H + titlebarH 43 }; 44 } 45 46 function centerPosition(shellW, shellH) { 47 return { 48 x: Math.max(8, Math.round((global.innerWidth - shellW) / 2)), 49 y: Math.max(8, Math.round((global.innerHeight - shellH - 48) / 2)) 50 }; 51 } 52 53 function openKitTv() { 54 var desktop = global.CitrusDesktop; 55 if (!desktop || typeof desktop.openAuxWindow !== 'function') return; 56 57 var shell = getShellSize(); 58 var pos = centerPosition(shell.w, shell.h); 59 desktop.openAuxWindow({ 60 id: AUX_ID, 61 label: 'Signal Lost\u2026', 62 icon: 'fa-solid fa-tv', 63 w: shell.w, 64 h: shell.h, 65 x: pos.x, 66 y: pos.y, 67 nearChat: false, 68 resizable: false, 69 auxClass: 'citrus-window--fixed-size citrus-window--kittv', 70 onMount: function (contentEl) { 71 contentEl.classList.add('citrus-window__content--iframe', 'citrusos-app-active'); 72 var iframe = document.createElement('iframe'); 73 iframe.className = 'citrus-window__iframe'; 74 iframe.title = 'KitTV'; 75 iframe.src = KITTV_URL; 76 iframe.setAttribute('referrerpolicy', 'no-referrer-when-downgrade'); 77 iframe.setAttribute('allow', 'fullscreen'); 78 iframe.setAttribute('allowfullscreen', ''); 79 contentEl.appendChild(iframe); 80 } 81 }); 82 } 83 84 function clearHoldTimer() { 85 if (holdTimer) { 86 clearTimeout(holdTimer); 87 holdTimer = null; 88 } 89 } 90 91 function onStartLogoPointerDown() { 92 clearHoldTimer(); 93 holdTriggered = false; 94 holdTimer = setTimeout(function () { 95 holdTimer = null; 96 holdTriggered = true; 97 openKitTv(); 98 }, HOLD_MS); 99 } 100 101 function onStartLogoPointerEnd() { 102 clearHoldTimer(); 103 } 104 105 function onStartBtnClick(ev) { 106 if (!holdTriggered) return; 107 ev.preventDefault(); 108 ev.stopPropagation(); 109 if (typeof ev.stopImmediatePropagation === 'function') { 110 ev.stopImmediatePropagation(); 111 } 112 holdTriggered = false; 113 } 114 115 function onClockClick() { 116 clockClickCount += 1; 117 if (clockClickTimer) clearTimeout(clockClickTimer); 118 if (clockClickCount >= 3) { 119 clockClickCount = 0; 120 clockClickTimer = null; 121 openKitTv(); 122 return; 123 } 124 clockClickTimer = setTimeout(function () { 125 clockClickCount = 0; 126 clockClickTimer = null; 127 }, TRIPLE_CLICK_MS); 128 } 129 130 function bindTriggers() { 131 var startLogo = qs('.citrusos-start-btn__logo'); 132 var startBtn = qs('#citrusos-start-btn'); 133 var clockTray = qs('.citrus-tray-clock'); 134 135 if (startLogo) { 136 startLogo.addEventListener('pointerdown', onStartLogoPointerDown); 137 startLogo.addEventListener('pointerup', onStartLogoPointerEnd); 138 startLogo.addEventListener('pointercancel', onStartLogoPointerEnd); 139 startLogo.addEventListener('pointerleave', onStartLogoPointerEnd); 140 } 141 142 if (startBtn) { 143 startBtn.addEventListener('click', onStartBtnClick, true); 144 } 145 146 if (clockTray) { 147 clockTray.addEventListener('click', onClockClick); 148 } 149 } 150
151 function init() { 152 if (!isCitrusDesktop()) return; 153 bindTriggers(); 154 } 155 156 if (document.readyState === 'loading') { 157 document.addEventListener('DOMContentLoaded', init); 158 } else { 159 init(); 160 } 161})(typeof window !== 'undefined' ? window : this);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.