feat(effects): sitewide effects suite — 25 CLI-triggered visual modes

This commit is contained in:
jae 2026-04-20 08:19:33 +00:00
parent 92db92423a
commit 2c498efbfb
16 changed files with 1747 additions and 239 deletions

View file

@ -1,42 +1,65 @@
{
"site": "jaeswift.xyz",
"entries": [
{
"version": "1.39.0",
"date": "20/04/2026",
"category": "FEATURE",
"title": "Sitewide Effects Suite \u2014 25 CLI-triggered visual modes",
"changes": [
"New /js/sitewide-effects.js (~1100 lines) + /css/sitewide-effects.css (~330 lines) \u2014 single central module, exposes window.__jaeEffects (toggle/enable/disable/active/disableAll)",
"Injected into 12 pages: index, hq/{telemetry,leaderboards,logs,briefing,profile,index}, depot/{contraband,recon}, recon, armoury/lab, transmissions/radar",
"VISUAL DISTORTION (7): /crt CRT scanlines + phosphor flicker + vignette; /vhs chromatic shift + roll bar + noise + glitch blocks; /glitch periodic text corruption + chroma shake; /redalert (/red alias) sepia-red filter + pulsing inset + Web Audio two-tone klaxon + DEFCON 1 banner; /invert; /blueprint hue-shift + grid overlay; /typewriter retype all text with click beeps",
"PHYSICS & MOTION (5): /gravity \u2014 panels + headings become fixed, fall with bounce physics; /earthquake \u2014 10s viewport shake; /lowgravity \u2014 1.2s transitions + floating bob; /melt \u2014 progressive vertical drip over 15s; /shuffle \u2014 scramble word order across visible text",
"ENVIRONMENTAL (5): /rain 200 drops + thunder flash + filtered-noise ambient; /snow 150 drifting flakes with sine sway; /fog dark overlay + torchlight circle around cursor; /night body dim + cursor spotlight via CSS vars; /underwater hue-rotate + wave overlay + bubble particles + lowpass noise",
"MIND-BENDING (3): /dimensions 3D perspective tilt tracking mouse; /portal \u2014 150px circular iframe lens following cursor showing random other page; /retro <1995|2005|2015|now> applies themed HTML classes (Comic Sans/yellow, Web 2.0 glossy, Material flat)",
"BONUS (5): /partymode disco hue-rotate + confetti + panel flashes + 120 BPM kick drum; /ghostmode invisible cursor + text fade until hover; /quantum panels teleport every 3s; /sneak replace all a/button labels with CLASSIFIED/REDACTED/etc; /hacker full-viewport scrolling fake code",
"Meta command /effects \u2014 shows ASCII status table of active effects; /effects off disables all; /effects all enables everything (chaos mode)",
"/matrix and /cmatrix migrated out of chat-cli.js into the sitewide-effects.js registry \u2014 commands stay identical but share the same single-source-of-truth module; dead toggleMatrix/toggleCMatrix code removed",
"Mobile + prefers-reduced-motion gating: all effects downgrade particle counts / disable audio gracefully on small screens or reduced-motion preference",
"Boss key (Escape / Ctrl+Shift+B) now calls window.__jaeEffects.disableAll() for a universal panic exit",
"Z-index ladder: 9000-9500 for overlays, 9600-9700 for loud UI (banners), leaves 9999+ for modals/toasts",
"CSS classes prefixed fx-* applied to <html> when active; each effect self-contained with enable/disable lifecycle, proper cleanup of RAF / intervals / AudioContext nodes / canvases",
"/help output extended with new EFFECTS category listing all 25 commands + /effects meta",
"Files: NEW js/sitewide-effects.js (1143 lines), NEW css/sitewide-effects.css (331 lines); MOD js/chat-cli.js (1142 \u2192 ~1129 lines \u2014 stripped 110 lines of matrix/cmatrix internals, added ~90 lines of thin command wrappers + EFFECTS help category); MOD 12 HTML files (+2 lines each for <link> + <script>)"
]
},
{
"version": "1.38.1",
"date": "20/04/2026",
"category": "FEATURE",
"title": "CLI Extensions: SSH, Adventure, Fortunes, Figlet, Achievements, Leaderboard, Boss Key",
"changes": [
"JAE-AI terminal (/) now has 7 new commands and 3 meta-features — type /help to see the categorised menu (SYSTEM / FUN / MODES / STATS)",
"/ssh <user>@<host> — fake SSH session with ED25519 handshake, MOTD, nested shell (ls/cat/cd/pwd/whoami/hostname/uname/date); exit via /exit-ssh or 'exit'",
"/adventure — short cyberpunk text adventure (DARK ALLEY → NEON ARCADE → HACKER DEN → LOW ROOFTOP → NEON ROOFTOP boss fight) with inventory, drone HP, /exit-adventure",
"/ttyper — typing-speed test with random programming quote, timer, WPM + accuracy calc, all-time best persisted in localStorage (jae-cli-ttyper-best-v1)",
"/cowsay <msg> — classic ASCII cow with auto-sized speech bubble",
"/figlet <text> — block-font ASCII banner (5-row UNICODE █ glyphs, full A-Z/0-9/punctuation, truncated to 20 chars)",
"/fortune -o — offensive mode with 30 crude operator-themed quips; /fortune alone returns 20 tame SITREP entries",
"/cmatrix — enhanced matrix rain: dual-colour green+cyan, denser (14px), speed ramps over 30s cycles, optional square-wave AudioContext ticks for typing-sound effect",
"/achievements — progress tracker showing X/24 commands discovered with ASCII progress bar [███░░░░░░░], list of unlocked commands, persists via localStorage (jae-cli-achievements-v1); toast pops for each new unlock",
"/leaderboard — session + all-time stats for this browser: command counts, unlocks, most-used command, top-5 session & all-time, military rank (recruit → general based on 20/50/100/200/500/1000/2000 thresholds)",
"Boss key — press Escape (while anything is 'hot') or Ctrl+Shift+B to instantly hide matrix rains, dev-mode badge, toasts, and clear chat input; shows 'NORMAL MODE' tooltip for ~2s",
"Nested mode routing — when inside /ssh, /adventure, /ttyper, plain (non-slash) chat input is routed to the nested handler instead of JAE-AI; chat.js updated with isInMode() check",
"Stats tracked in localStorage (jae-cli-stats-v1) and in-memory session counter; commands object grown from 17 → 24",
"Files: js/chat-cli.js (+632 lines → 1142 total), css/chat-cli.css (+21 lines), js/chat.js (+1 line — mode-aware CLI interception)"
"JAE-AI terminal (/) now has 7 new commands and 3 meta-features \u2014 type /help to see the categorised menu (SYSTEM / FUN / MODES / STATS)",
"/ssh <user>@<host> \u2014 fake SSH session with ED25519 handshake, MOTD, nested shell (ls/cat/cd/pwd/whoami/hostname/uname/date); exit via /exit-ssh or 'exit'",
"/adventure \u2014 short cyberpunk text adventure (DARK ALLEY \u2192 NEON ARCADE \u2192 HACKER DEN \u2192 LOW ROOFTOP \u2192 NEON ROOFTOP boss fight) with inventory, drone HP, /exit-adventure",
"/ttyper \u2014 typing-speed test with random programming quote, timer, WPM + accuracy calc, all-time best persisted in localStorage (jae-cli-ttyper-best-v1)",
"/cowsay <msg> \u2014 classic ASCII cow with auto-sized speech bubble",
"/figlet <text> \u2014 block-font ASCII banner (5-row UNICODE \u2588 glyphs, full A-Z/0-9/punctuation, truncated to 20 chars)",
"/fortune -o \u2014 offensive mode with 30 crude operator-themed quips; /fortune alone returns 20 tame SITREP entries",
"/cmatrix \u2014 enhanced matrix rain: dual-colour green+cyan, denser (14px), speed ramps over 30s cycles, optional square-wave AudioContext ticks for typing-sound effect",
"/achievements \u2014 progress tracker showing X/24 commands discovered with ASCII progress bar [\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591], list of unlocked commands, persists via localStorage (jae-cli-achievements-v1); toast pops for each new unlock",
"/leaderboard \u2014 session + all-time stats for this browser: command counts, unlocks, most-used command, top-5 session & all-time, military rank (recruit \u2192 general based on 20/50/100/200/500/1000/2000 thresholds)",
"Boss key \u2014 press Escape (while anything is 'hot') or Ctrl+Shift+B to instantly hide matrix rains, dev-mode badge, toasts, and clear chat input; shows 'NORMAL MODE' tooltip for ~2s",
"Nested mode routing \u2014 when inside /ssh, /adventure, /ttyper, plain (non-slash) chat input is routed to the nested handler instead of JAE-AI; chat.js updated with isInMode() check",
"Stats tracked in localStorage (jae-cli-stats-v1) and in-memory session counter; commands object grown from 17 \u2192 24",
"Files: js/chat-cli.js (+632 lines \u2192 1142 total), css/chat-cli.css (+21 lines), js/chat.js (+1 line \u2014 mode-aware CLI interception)"
]
},
{
"version": "1.38.0",
"date": "20/04/2026",
"category": "FEATURE",
"title": "Globe Live Traffic Arcs from Real Visitors",
"title": "Globe \u2014 Live Traffic Arcs from Real Visitors",
"changes": [
"Homepage 3D globe (globe.gl) now draws glowing arcs from real visitor country centroids into Manchester HQ (53.48°N, -2.24°W) instead of random fake cities",
"Data sourced live from /api/visitor/recent-arcs — tails last 20k lines of nginx access.log, GeoIPs unique IPs, maps country_code → centroid (130+ countries in api/data/country_centroids.json)",
"Homepage 3D globe (globe.gl) now draws glowing arcs from real visitor country centroids into Manchester HQ (53.48\u00b0N, -2.24\u00b0W) instead of random fake cities",
"Data sourced live from /api/visitor/recent-arcs \u2014 tails last 20k lines of nginx access.log, GeoIPs unique IPs, maps country_code \u2192 centroid (130+ countries in api/data/country_centroids.json)",
"Frontend polls endpoint every 30s; tactical green arcs (rgba(0,255,60,.85)) fade to turquoise Solana (#14F195) tail for depth, 2.2s dash animation, 0.38 altitude auto-scale",
"Per-arc interactive labels on hover: \"COUNTRY → MCR · Xm ago · /page_path\"",
"Per-arc interactive labels on hover: \"COUNTRY \u2192 MCR \u00b7 Xm ago \u00b7 /page_path\"",
"New ARCS LIVE counter badge added to globe overlay HUD (turquoise accent), updates with each refresh",
"Sub-degree lat/lon jitter applied so multiple visitors from same country no longer stack on a single line",
"Graceful fallback: if endpoint returns empty/errors, shows 8 demo city arcs (New York/Tokyo/Paris/Sydney/Moscow/Singapore/Berlin/LA) so the globe is never bare",
"Timestamp parser handles nginx common-log format (DD/Mon/YYYY:HH:MM:SS ±ZZZZ) for accurate relative times",
"Timestamp parser handles nginx common-log format (DD/Mon/YYYY:HH:MM:SS \u00b1ZZZZ) for accurate relative times",
"Backend endpoint cache: 5-min TTL, deduped by IP, capped at 50 most-recent unique visitors"
]
},
@ -44,19 +67,19 @@
"version": "1.37.2",
"date": "20/04/2026",
"category": "FEATURE",
"title": "LEADERBOARDS Live Operational Rankings",
"title": "LEADERBOARDS \u2014 Live Operational Rankings",
"changes": [
"New page /hq/leaderboards with 6-panel grid showing real-time traffic intelligence pulled from nginx access logs",
"TOP COUNTRIES (24h): GeoIP-resolved top 15 origins with auto-generated flag emojis and animated ranked bars",
"TOP PAGES (24h): most-hit routes (API/CSS/JS/favicons filtered out), top 20 with green-code path display",
"TOP REFERRERS (7d): inbound link sources filtered for own domain graceful empty state for direct-traffic sites",
"TOP REFERRERS (7d): inbound link sources filtered for own domain \u2014 graceful empty state for direct-traffic sites",
"PEAK HOURS (24h UTC): 24-bar hourly chart with amber-highlighted peak column, hover tooltips, auto-summary showing peak hour + total req/24h",
"BROWSER BREAKDOWN (24h): top 10 UA families with per-browser emoji (🟢 Chrome / 🦊 Firefox / 🧭 Safari / 🌀 Edge / 🤖 Bot)",
"OPERATOR LEADERBOARD (7d): top 10 most-active IPs (privacy-masked first/last octet), request counts, last-seen relative timestamps self-IP highlighted with amber (YOU) badge",
"Gold/silver/bronze rank styling for top-3 rows across all panels; #01#NN zero-padded ranks elsewhere",
"BROWSER BREAKDOWN (24h): top 10 UA families with per-browser emoji (\ud83d\udfe2 Chrome / \ud83e\udd8a Firefox / \ud83e\udded Safari / \ud83c\udf00 Edge / \ud83e\udd16 Bot)",
"OPERATOR LEADERBOARD (7d): top 10 most-active IPs (privacy-masked first/last octet), request counts, last-seen relative timestamps \u2014 self-IP highlighted with amber (YOU) badge",
"Gold/silver/bronze rank styling for top-3 rows across all panels; #01\u2013#NN zero-padded ranks elsewhere",
"60s auto-refresh + manual refresh button + live LAST UPDATED counter (ticks per second)",
"Backend /api/leaderboards endpoint returns JSON aggregating countries, pages, referrers, peak_hours, browsers, top_operators 60s in-memory cache",
"New files: hq/leaderboards.html · css/leaderboards.css · js/leaderboards.js",
"Backend /api/leaderboards endpoint returns JSON aggregating countries, pages, referrers, peak_hours, browsers, top_operators \u2014 60s in-memory cache",
"New files: hq/leaderboards.html \u00b7 css/leaderboards.css \u00b7 js/leaderboards.js",
"Nav updated: HQ menu now includes LEADERBOARDS link with description \"Live traffic rankings & operator stats\"",
"Fully mobile responsive (768px stack / 420px compact) with scanlines + grid-bg matching site theme"
]
@ -65,31 +88,31 @@
"version": "1.37.1",
"date": "20/04/2026",
"category": "FEATURE",
"title": "JAE-AI CLI Easter Egg Local Pseudo-Shell",
"title": "JAE-AI CLI Easter Egg \u2014 Local Pseudo-Shell",
"changes": [
"JAE-AI chat now detects messages starting with / and handles them locally as a fake CLI shell never hits the Venice API, all 100% client-side JavaScript",
"New js/chat-cli.js + css/chat-cli.css 17 built-in commands: /help /ls /cat <file> /whoami /uptime /uname -a /date /ping <host> /sudo <cmd> /rm -rf / /hack <target> /matrix /clear /exit /fortune /history /neofetch",
"Virtual filesystem: /cat about.md|projects.json|skills.md|secrets.enc|mascot.txt|whoami.txt with glitchy ASCII art ACCESS DENIED screen on secrets.enc",
"JAE-AI chat now detects messages starting with / and handles them locally as a fake CLI shell \u2014 never hits the Venice API, all 100% client-side JavaScript",
"New js/chat-cli.js + css/chat-cli.css \u2014 17 built-in commands: /help /ls /cat <file> /whoami /uptime /uname -a /date /ping <host> /sudo <cmd> /rm -rf / /hack <target> /matrix /clear /exit /fortune /history /neofetch",
"Virtual filesystem: /cat about.md|projects.json|skills.md|secrets.enc|mascot.txt|whoami.txt \u2014 with glitchy ASCII art ACCESS DENIED screen on secrets.enc",
"/whoami pulls real data from /api/visitor/scan; /uptime pulls from /api/telemetry/overview; /neofetch shows ASCII dragon with browser/OS/screen data",
"/matrix toggles a full-screen green Katakana matrix-rain canvas overlay (opacity 18%, 16px JetBrains Mono, var(--status-green))",
"/hack runs hollywood-style fake progress bars with payload injection drama before revealing it was all fake",
"/rm -rf / shows an ASCII destruction sequence then restores from backup with a cheeky message",
"Unknown commands route to: command not found: /<cmd>. Type /help for available commands.",
"Persistent /history ring-buffer (50 entries) stored in localStorage.jaeCliHist",
"BONUS: Konami code (↑↑↓↓←→←→BA) unlocks DEVELOPER MODE — amber badge top-right + extra commands: /api (list real endpoints), /curl <url> (actually fetch public URLs, 2KB truncated), /geo (pull live 24h country breakdown from telemetry)",
"chat.js sendMessage() patched to intercept /-prefix messages before hitting /api/chat user bubble gets $ shell prompt, response styled in terminal-green monospace"
"BONUS: Konami code (\u2191\u2191\u2193\u2193\u2190\u2192\u2190\u2192BA) unlocks DEVELOPER MODE \u2014 amber badge top-right + extra commands: /api (list real endpoints), /curl <url> (actually fetch public URLs, 2KB truncated), /geo (pull live 24h country breakdown from telemetry)",
"chat.js sendMessage() patched to intercept /-prefix messages before hitting /api/chat \u2014 user bubble gets $ shell prompt, response styled in terminal-green monospace"
]
},
{
"version": "1.37.0",
"date": "20/04/2026",
"category": "FEATURE",
"title": "SCAN THE VISITOR Typewriter Operator Recon Overlay",
"title": "SCAN THE VISITOR \u2014 Typewriter Operator Recon Overlay",
"changes": [
"New homepage overlay greets every visitor with a dramatic typewriter-animated recon scan (~22ms/char): geolocation via GeoLite2, reverse-DNS-derived ISP, user-agent parsing (browser/OS/device) via user-agents pip package, masked IP (X.***.***.Y), screen/language/timezone/connection fingerprinting, plus GREEN/AMBER/RED threat-level status bar",
"Backend: new api/visitor_routes.py Flask blueprint with /api/visitor/scan endpoint in-memory per-IP rate limiting (1 req / 10s), lazy GeoIP reader (country + city when available), 1s-timeout reverse DNS hostname lookup with ISP dictionary (BT/Virgin/Sky/AWS/Cloudflare/Hetzner etc.), country-flag emoji auto-generation, TOR exit-node heuristic",
"Frontend: js/scan-visitor.js + css/scan-visitor.css 720px CRT-scanline overlay with blur backdrop, monospace green typewriter output, blink cursor, three action buttons (CLOSE / DISMISS 7D / ACKNOWLEDGE), ESC-to-close, collapses into a persistent bottom-right OPERATOR ID badge on close, click badge to re-run scan",
"localStorage persistence: scanDismissed (7-day auto-expiry so returning operators only see the badge), scanBadgeHidden (× on badge hides it permanently)",
"Backend: new api/visitor_routes.py Flask blueprint with /api/visitor/scan endpoint \u2014 in-memory per-IP rate limiting (1 req / 10s), lazy GeoIP reader (country + city when available), 1s-timeout reverse DNS hostname lookup with ISP dictionary (BT/Virgin/Sky/AWS/Cloudflare/Hetzner etc.), country-flag emoji auto-generation, TOR exit-node heuristic",
"Frontend: js/scan-visitor.js + css/scan-visitor.css \u2014 720px CRT-scanline overlay with blur backdrop, monospace green typewriter output, blink cursor, three action buttons (CLOSE / DISMISS 7D / ACKNOWLEDGE), ESC-to-close, collapses into a persistent bottom-right OPERATOR ID badge on close, click badge to re-run scan",
"localStorage persistence: scanDismissed (7-day auto-expiry so returning operators only see the badge), scanBadgeHidden (\u00d7 on badge hides it permanently)",
"Fully mobile responsive: panel narrows to 96vw at <600px, reduces typography, adjusts badge position above bottom HUD bar",
"Bundled api/data/country_centroids.json (130+ ISO-3166 country lat/lon centroids) to power upcoming 3D globe traffic-arc feature",
"Exposed window.__jaeScan.run() / window.__jaeScan.reset() for debug re-triggering"
@ -99,12 +122,12 @@
"version": "1.36.2",
"date": "20/04/2026",
"category": "FIX",
"title": "Telemetry Polish GeoIP Live, Service Watchlist Cleanup, Git Hygiene",
"title": "Telemetry Polish \u2014 GeoIP Live, Service Watchlist Cleanup, Git Hygiene",
"changes": [
"GEO INTEL panel now LIVE installed DB-IP Country Lite mmdb (8.4MB, April 2026) at /usr/share/GeoIP/GeoLite2-Country.mmdb on VPS plus geoip2==5.2.0 Python package; telemetry dashboard now shows per-country traffic bars (US/GB/RU/CN/SG/DE/AD/UA currently top)",
"GEO INTEL panel now LIVE \u2014 installed DB-IP Country Lite mmdb (8.4MB, April 2026) at /usr/share/GeoIP/GeoLite2-Country.mmdb on VPS plus geoip2==5.2.0 Python package; telemetry dashboard now shows per-country traffic bars (US/GB/RU/CN/SG/DE/AD/UA currently top)",
"Monthly GeoIP auto-refresh: new /usr/local/bin/update-geoip.sh bash script + cron '0 4 2 * *' fetches fresh DB-IP mmdb on 2nd of each month, gunzips, restarts jaeswift-api.service, logs to /var/log/geoip-update.log",
"Service watchlist cleaned removed matty-lol, caddy, n8n from SYSTEMD_SERVICES in telemetry_routes.py (they were generating false SERVICE DOWN alerts; matty-lol runs on PM2, caddy+n8n unused)",
"Git DIRTY flag cleared added runtime-generated files to .gitignore: api/data/telemetry_history.json, api/data/telemetry_netstate.json, api/govdomains-source/ (these are written by cron jobs, not source code)",
"Service watchlist cleaned \u2014 removed matty-lol, caddy, n8n from SYSTEMD_SERVICES in telemetry_routes.py (they were generating false SERVICE DOWN alerts; matty-lol runs on PM2, caddy+n8n unused)",
"Git DIRTY flag cleared \u2014 added runtime-generated files to .gitignore: api/data/telemetry_history.json, api/data/telemetry_netstate.json, api/govdomains-source/ (these are written by cron jobs, not source code)",
"Repos panel now reports CLEAN instead of DIRTY for jaeswift-homepage"
]
},
@ -114,8 +137,8 @@
"category": "FIX",
"title": "Cron Log Path Corrections",
"changes": [
"Fixed CRON_JOBS definitions in telemetry_routes.py contraband/awesomelist/govdomains logs use hyphens not underscores on VPS (contraband-sync.log not contraband_sync.log)",
"Corrected govdomains_sync schedule from Sunday 05:00 to every 12 hours (0 */12 * * *) matches actual crontab",
"Fixed CRON_JOBS definitions in telemetry_routes.py \u2014 contraband/awesomelist/govdomains logs use hyphens not underscores on VPS (contraband-sync.log not contraband_sync.log)",
"Corrected govdomains_sync schedule from Sunday 05:00 to every 12 hours (0 */12 * * *) \u2014 matches actual crontab",
"All 5 crons now report OK status on telemetry dashboard instead of UNKNOWN"
]
},
@ -123,30 +146,30 @@
"version": "1.36.0",
"date": "19/04/2026",
"category": "FEATURE",
"title": "TELEMETRY Dashboard Live Ops Command Centre",
"title": "TELEMETRY Dashboard \u2014 Live Ops Command Centre",
"changes": [
"New /hq/telemetry page replacing placeholder full live ops dashboard with boot sequence animation, CRT aesthetic, real-time metrics",
"Backend blueprint api/telemetry_routes.py 6 new endpoints: /api/telemetry/overview, /history, /nginx-tail, /geo, /alerts, /visitors, /commits",
"New /hq/telemetry page replacing placeholder \u2014 full live ops dashboard with boot sequence animation, CRT aesthetic, real-time metrics",
"Backend blueprint api/telemetry_routes.py \u2014 6 new endpoints: /api/telemetry/overview, /history, /nginx-tail, /geo, /alerts, /visitors, /commits",
"System metrics: CPU gauge + 24h sparkline, memory gauge + sparkline, per-mount disk ASCII bars, network RX/TX rates + history graph, uptime, load avg, kernel",
"Services panel: systemctl state for jaeswift-api, matty-lol, nginx, filebrowser, caddy, n8n, docker, ssh — plus PM2 processes — with uptime, mem, CPU per service",
"Cron tracker: schedule + last run + status (ok/fail/unknown) for contraband_sync, awesomelist_sync, govdomains_sync, sitrep, telemetry_snapshot expandable log tails",
"Nginx 24h analytics: total requests, bandwidth, avg RPM, top 10 pages, top 10 IPs (masked), 4xx/5xx counts, avg response time 60s cache",
"Services panel: systemctl state for jaeswift-api, matty-lol, nginx, filebrowser, caddy, n8n, docker, ssh \u2014 plus PM2 processes \u2014 with uptime, mem, CPU per service",
"Cron tracker: schedule + last run + status (ok/fail/unknown) for contraband_sync, awesomelist_sync, govdomains_sync, sitrep, telemetry_snapshot \u2014 expandable log tails",
"Nginx 24h analytics: total requests, bandwidth, avg RPM, top 10 pages, top 10 IPs (masked), 4xx/5xx counts, avg response time \u2014 60s cache",
"Security panel: fail2ban jails + ban counts, UFW rules, SSH bruteforce attempts 24h, last reboot timestamp",
"SSL expiry tracker: per-domain days-remaining with colour coding (red <14d, amber <30d, green otherwise) for jaeswift.xyz, git, files, plex, agentzero",
"Stack inventory: auto-detected versions of Python, Node, nginx, Docker, ffmpeg, kernel, OS cached at startup",
"Stack inventory: auto-detected versions of Python, Node, nginx, Docker, ffmpeg, kernel, OS \u2014 cached at startup",
"Git activity panel: repo name, last commit SHA, message, timestamp, dirty flag for /var/www/jaeswift-homepage",
"Geo-distribution: parses nginx IPs through GeoLite2 mmdb (if installed) horizontal bar chart of top 15 countries by traffic, graceful empty state if mmdb missing",
"Geo-distribution: parses nginx IPs through GeoLite2 mmdb (if installed) \u2014 horizontal bar chart of top 15 countries by traffic, graceful empty state if mmdb missing",
"Live nginx tail widget: last 20 requests auto-scrolling every 5s with fade-in animation, colour-coded status codes, masked IPs",
"Alert engine: real-time /api/telemetry/alerts computes CPU/mem/disk/service/cron/5xx/SSL/SSH thresholds — red/amber/info levels — scrolling marquee banner on page",
"Visitor counter: active unique IPs in last 5min + req/min animated ONLINE NOW strong number",
"Burn rate panel: free disk GB, 24h bandwidth totals (↑/↓), load avg breakdown, kernel@hostname",
"Alert engine: real-time /api/telemetry/alerts computes CPU/mem/disk/service/cron/5xx/SSL/SSH thresholds \u2014 red/amber/info levels \u2014 scrolling marquee banner on page",
"Visitor counter: active unique IPs in last 5min + req/min \u2014 animated ONLINE NOW strong number",
"Burn rate panel: free disk GB, 24h bandwidth totals (\u2191/\u2193), load avg breakdown, kernel@hostname",
"Deployment ticker: horizontal marquee of last 10 git commits (SHA + message + ago)",
"Boot animation: 1.5s cinematic sequence — INITIALISING → SECURE CHANNEL → DECRYPTING → AUTHORISED — with progress bar, fades out to reveal grid",
"Boot animation: 1.5s cinematic sequence \u2014 INITIALISING \u2192 SECURE CHANNEL \u2192 DECRYPTING \u2192 AUTHORISED \u2014 with progress bar, fades out to reveal grid",
"Alarm sound toggle: Web Audio API generates beep on new alert (urgent=880Hz for red, 440Hz for amber), default OFF, speaker icon top-right",
"Blinking LIVE indicator showing last-sync seconds, dot colour shifts green→amber→red as staleness grows",
"Mobile responsive all 7 rows stack to single column below 768px, alerts shrink, grid reflows",
"Blinking LIVE indicator showing last-sync seconds, dot colour shifts green\u2192amber\u2192red as staleness grows",
"Mobile responsive \u2014 all 7 rows stack to single column below 768px, alerts shrink, grid reflows",
"New api/telemetry_snapshot.py ring-buffer cron (every 5min) appends CPU/mem/net to api/data/telemetry_history.json (288 points = 24h)",
"New styles: css/telemetry.css (~620 lines) with full dashboard grid, canvas gauges, ASCII disk bars, terminal tail, geo chart, marquee banners all theming existing var(--tm-green/amber/red/sol) CRT scheme"
"New styles: css/telemetry.css (~620 lines) with full dashboard grid, canvas gauges, ASCII disk bars, terminal tail, geo chart, marquee banners \u2014 all theming existing var(--tm-green/amber/red/sol) CRT scheme"
]
},
{
@ -172,9 +195,9 @@
"Chat history persistence across page reloads (last 50 messages in localStorage key jae-ai-history-v1, auto-restored with RESTORED FROM MEMORY divider)",
"Memory Vault modal UI: military/terminal themed, grouped by category (identity/preference/project/skill/goal/relationship/other) with per-entry delete, importance/timestamp display",
"Modal controls: EXPORT JSON (download backup), FORCE EXTRACT (manual trigger), CLEAR HISTORY (wipes conversation), CLEAR ALL MEMORIES (with confirm)",
"Memory button in chat header with live count badge + privacy info tooltip () explaining local-only storage",
"Memory button in chat header with live count badge + privacy info tooltip (\u2139) explaining local-only storage",
"Fuzzy dedup: new memories >80% similar to existing are merged (importance boosted) instead of duplicated",
"Privacy-first design: all memories stay in the users browser; only current query + small relevant subset sent to Venice per message",
"Privacy-first design: all memories stay in the user\u2019s browser; only current query + small relevant subset sent to Venice per message",
"Graceful degradation: missing localStorage or extraction failures never break the chat loop"
]
},
@ -182,7 +205,7 @@
"version": "1.33.0",
"date": "19/04/2026",
"category": "FEATURE",
"title": "Homepage SERVER METRICS Real Live Data",
"title": "Homepage SERVER METRICS \u2014 Real Live Data",
"changes": [
"SERVER METRICS panel now shows real VPS metrics via /api/stats",
"CPU LOAD bar: real load_avg / nproc percentage",
@ -211,7 +234,7 @@
"Purged file from entire git history via git-filter-repo (all 120 commits rewritten)",
"Force-pushed cleaned history to Gitea (old commits garbage-collected)",
"Created apikeys.example.json template for future contributors",
"Rotated Venice API key old key revoked by user",
"Rotated Venice API key \u2014 old key revoked by user",
"VPS file permissions hardened: chmod 600 api/data/apikeys.json",
"Verified raw URL git.jaeswift.xyz/.../apikeys.json now returns HTTP 404",
"Audit confirmed: zero occurrences of any API key in git history across all branches"
@ -221,21 +244,21 @@
"version": "1.31.0",
"date": "19/04/2026",
"category": "AI",
"title": "AI Model Switch Gemma-4-Uncensored",
"title": "AI Model Switch \u2014 Gemma-4-Uncensored",
"changes": [
"Switched JAE AI chat model from olafangensan-glm-4.7-flash-heretic to gemma-4-uncensored",
"Switched SITREP daily briefing generator to same model for consistency",
"Updated admin panel chat defaults: model + header tag now reflect GEMMA-4-UNCENSORED",
"API restarted and verified live chat now returns tighter, more natural replies"
"API restarted and verified live \u2014 chat now returns tighter, more natural replies"
]
},
{
"version": "v1.30.0",
"date": "18/04/2026",
"title": "ARMOURY: Wallet X-Ray Solana Wallet Analyser",
"title": "ARMOURY: Wallet X-Ray \u2014 Solana Wallet Analyser",
"category": "ARMOURY",
"changes": [
"New tool: Wallet X-Ray deep scan any Solana wallet address or connect your own wallet",
"New tool: Wallet X-Ray \u2014 deep scan any Solana wallet address or connect your own wallet",
"Overview panel: SOL balance with live USD value, total portfolio value, wallet age, transaction count, and activity rating",
"Token Holdings: full SPL token table with logos, balances, live prices via Jupiter Price API, and USD values sorted by value",
"NFT Detection: identifies NFTs (0-decimal single-supply tokens) with image grid and Solscan links",
@ -247,7 +270,7 @@
"URL parameter support: ?address=... for direct wallet scanning via shared links",
"Wallet X-Ray card added to LAB page with cyan/turquoise theme",
"Military radar sweep loading animation during wallet scan",
"Fully responsive design works on mobile and desktop"
"Fully responsive design \u2014 works on mobile and desktop"
]
},
{
@ -257,14 +280,14 @@
"category": "UNREDACTED",
"changes": [
"Added 9 new collections across UFO/UAP, Covert Operations, and Government categories with 15 indexed documents",
"COMETA Report (France, 1999): 2 English translations of landmark French military UFO assessment 163 pages total",
"RAAF UFO Files (Australia): Declassified Royal Australian Air Force intelligence file 18 pages",
"Project Magnet (Canada, 1950-54): Official Canadian government UFO research programme documents 6 pages",
"NZDF UFO/UAP Files (New Zealand, 1984-2024): 3 documents including Cold War sighting reports and modern OIA responses 136 pages",
"Operação Prato (Brazil, 1977): Secret Brazilian Air Force UFO investigation in the Amazon — 58 pages",
"COMETA Report (France, 1999): 2 English translations of landmark French military UFO assessment \u2014 163 pages total",
"RAAF UFO Files (Australia): Declassified Royal Australian Air Force intelligence file \u2014 18 pages",
"Project Magnet (Canada, 1950-54): Official Canadian government UFO research programme documents \u2014 6 pages",
"NZDF UFO/UAP Files (New Zealand, 1984-2024): 3 documents including Cold War sighting reports and modern OIA responses \u2014 136 pages",
"Opera\u00e7\u00e3o Prato (Brazil, 1977): Secret Brazilian Air Force UFO investigation in the Amazon \u2014 58 pages",
"COINTELPRO: 758-page FBI surveillance programme compilation plus analytical examination added to existing collection",
"Operation Paperclip (1945-59): Declassified CIA documents on Nazi scientist recruitment programme 11 pages",
"Watergate Scandal (1972-74): Ford Presidential Library documents on the constitutional crisis 35 pages",
"Operation Paperclip (1945-59): Declassified CIA documents on Nazi scientist recruitment programme \u2014 11 pages",
"Watergate Scandal (1972-74): Ford Presidential Library documents on the constitutional crisis \u2014 35 pages",
"Iran-Contra Affair (1985-87): Complete 506-page Congressional investigation report",
"New countries added to UFO/UAP category: France, Australia, Canada, New Zealand, Brazil"
]
@ -276,12 +299,12 @@
"category": "CRIME SCENE",
"changes": [
"Added 6 new crime case collections across cold-cases, serial-killers, and landmark-cases with 11 indexed documents",
"D.B. Cooper Hijacking (1971): FBI investigation files 162 pages on America's only unsolved aircraft hijacking",
"JonBenét Ramsey Murder (1996): Autopsy report, unsealed grand jury indictment, and analytical case study — 19 pages",
"Black Dahlia / Elizabeth Short (1947): Complete FBI investigation file 204 pages on LA's most famous unsolved murder",
"Delphi Murders (2017): Probable cause affidavit and court documents from the Richard Allen prosecution 95 pages",
"Harold Shipman (1975-98): First three reports of the Shipman Inquiry (Dame Janet Smith) 1,162 pages on Britain's worst serial killer",
"Moors Murders — Brady & Hindley (1963-65): Mental Health Review Tribunal academic paper — 22 pages",
"D.B. Cooper Hijacking (1971): FBI investigation files \u2014 162 pages on America's only unsolved aircraft hijacking",
"JonBen\u00e9t Ramsey Murder (1996): Autopsy report, unsealed grand jury indictment, and analytical case study \u2014 19 pages",
"Black Dahlia / Elizabeth Short (1947): Complete FBI investigation file \u2014 204 pages on LA's most famous unsolved murder",
"Delphi Murders (2017): Probable cause affidavit and court documents from the Richard Allen prosecution \u2014 95 pages",
"Harold Shipman (1975-98): First three reports of the Shipman Inquiry (Dame Janet Smith) \u2014 1,162 pages on Britain's worst serial killer",
"Moors Murders \u2014 Brady & Hindley (1963-65): Mental Health Review Tribunal academic paper \u2014 22 pages",
"New landmark-cases/US subcategory with Delphi Murders as first entry",
"Total new document pages added: 1,664 across all crime scene collections"
]
@ -289,18 +312,18 @@
{
"version": "v1.27.0",
"date": "18/04/2026",
"title": "CRIME SCENE: UK Murder Cases Mass Upload",
"title": "CRIME SCENE: UK Murder Cases \u2014 Mass Upload",
"category": "CRIME SCENE",
"changes": [
"Added 11 UK murder case collections across 4 categories with 57 indexed documents",
"New 'Landmark Cases' category for cases that changed British law and policing",
"Daniel Morgan (1987): 3-volume Independent Panel Report 1,276 pages on Met Police corruption",
"Daniel Morgan (1987): 3-volume Independent Panel Report \u2014 1,276 pages on Met Police corruption",
"Claudia Lawrence (2009): ICO FOI audit of North Yorkshire Police practices",
"Jill Dando (1999): Barry George appeal judgment and CCRC referral decision",
"Suzy Lamplugh (1986): Suzy Lamplugh Trust safety resources and case documentation",
"Stephen Lawrence (1993): Complete Macpherson Report 389 pages, coined 'institutional racism'",
"Stephen Lawrence (1993): Complete Macpherson Report \u2014 389 pages, coined 'institutional racism'",
"James Bulger (1993): ECHR Grand Chamber judgments, anonymity injunction, minimum term review",
"Damilola Taylor (2000): Sentamu Oversight Panel investigation review 56 pages",
"Damilola Taylor (2000): Sentamu Oversight Panel investigation review \u2014 56 pages",
"Lee Rigby (2013): ISC intelligence report (200 pages), Government response, sentencing remarks",
"Lord Lucan (1974): Presumption of Death Act legal analysis for Sandra Rivett murder",
"Madeleine McCann (2007): PJ Police Report translation (57 pages), Jane Tanner statements (4 parts)",
@ -315,10 +338,10 @@
"category": "CRIME SCENE",
"changes": [
"Populated the Police Reports subcollection for the Zodiac Killer with 5 documents (207 pages, 26.4 MB)",
"Added Lake Herman Road police reports Benicia PD & Solano County Sheriff (60 pages, 5.6 MB)",
"Added Blue Rock Springs police reports Vallejo PD (75 pages, 10.3 MB)",
"Added Lake Berryessa police reports Napa County Sheriff's Office (35 pages, 5.1 MB)",
"Added Presidio Heights / Paul Stine police reports SFPD (2 pages, 0.4 MB)",
"Added Lake Herman Road police reports \u2014 Benicia PD & Solano County Sheriff (60 pages, 5.6 MB)",
"Added Blue Rock Springs police reports \u2014 Vallejo PD (75 pages, 10.3 MB)",
"Added Lake Berryessa police reports \u2014 Napa County Sheriff's Office (35 pages, 5.1 MB)",
"Added Presidio Heights / Paul Stine police reports \u2014 SFPD (2 pages, 0.4 MB)",
"Added California Department of Justice investigation report (35 pages, 5.0 MB)",
"Zodiac Killer collection now contains 26 documents across 4 subcollections totalling approximately 78 MB",
"All documents sourced from zodiackiller.com's authenticated police report archive"
@ -327,7 +350,7 @@
{
"version": "1.25.0",
"date": "16/04/2026",
"title": "Changelog Fix Date Format & Missing Entries",
"title": "Changelog Fix \u2014 Date Format & Missing Entries",
"category": "fix",
"changes": [
"Fixed NaN/NaN/NaN date display bug in changelog renderer",
@ -344,18 +367,18 @@
"category": "fix",
"changes": [
"Replaced encrypted/unreadable MKUltra PDF with two working documents",
"Added CIA Inspector General Report (1963) 48-page TOP SECRET internal review",
"Added Senate Hearing transcript (1977) 171-page Congressional testimony exposing 149 sub-projects"
"Added CIA Inspector General Report (1963) \u2014 48-page TOP SECRET internal review",
"Added Senate Hearing transcript (1977) \u2014 171-page Congressional testimony exposing 149 sub-projects"
]
},
{
"version": "1.23.0",
"date": "16/04/2026",
"title": "PROPAGANDA UNREDACTED Rename + Nav Animation + CRIME SCENE",
"title": "PROPAGANDA \u2192 UNREDACTED Rename + Nav Animation + CRIME SCENE",
"category": "feature",
"changes": [
"Renamed PROPAGANDA section to UNREDACTED across all pages, nav, API, and URLs",
"Built block-reveal animation on UNREDACTED nav item (██████████ → UNREDACTED → reverse → loop)",
"Built block-reveal animation on UNREDACTED nav item (\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2192 UNREDACTED \u2192 reverse \u2192 loop)",
"Added global document search across all UNREDACTED categories, titles, and descriptions",
"Built new CRIME SCENE section at /depot/crimescene with red CRT theme",
"Four crime categories: Unsolved Murders, Serial Killers, Court Transcripts, Cold Cases",
@ -366,12 +389,12 @@
{
"version": "1.22.0",
"date": "15/04/2026",
"title": "CRIME SCENE: Zodiac Killer Expanded Letters, Ciphers & Subcollections",
"title": "CRIME SCENE: Zodiac Killer Expanded \u2014 Letters, Ciphers & Subcollections",
"category": "CRIME SCENE",
"changes": [
"Fixed PDF path bug: document URLs now correctly include country code (US) via subcollection routing",
"Restructured Zodiac Killer into 4 subcollections: FBI Investigation Files, Zodiac Letters & Cards, The Zodiac Ciphers, Police Reports & Crime Scene Documents",
"Added 11 original Zodiac letter PDFs (19691974) from zodiackiller.com: Chronicle/Examiner cipher letters, Debut letter, Stine bloody shirt letter, Bus Bomb letter, Belli letter, Dragon card, Phillips 66 map letter, Little List/Mikado letter, Exorcist letter, Citizen card",
"Added 11 original Zodiac letter PDFs (1969\u20131974) from zodiackiller.com: Chronicle/Examiner cipher letters, Debut letter, Stine bloody shirt letter, Bus Bomb letter, Belli letter, Dragon card, Phillips 66 map letter, Little List/Mikado letter, Exorcist letter, Citizen card",
"Added 3 cipher PDFs: Z408 three-part cipher (solved 1969), Z340 cipher (solved 2020), Z32 map code cipher (unsolved)",
"Added Z340 Solution academic paper by Oranchak, Blake & Van Eycke (2024, 38 pages) from arXiv",
"Each of the 21 new documents has a unique historical description with contextual detail",
@ -387,7 +410,7 @@
"category": "CRIME SCENE",
"changes": [
"Added complete FBI Zodiac Killer investigation files (6 parts, 1,116 pages, 34MB)",
"Files sourced from FBI Vault via Archive.org declassified FOIA release",
"Files sourced from FBI Vault via Archive.org \u2014 declassified FOIA release",
"Each document includes unique summary describing specific contents",
"Covers: Arthur Leigh Allen suspect investigation, cipher analysis, forensic lab reports, fingerprint comparisons, decades of tips and suspect referrals",
"PDFs served from /crimescene/docs/serial-killers/US/zodiac-killer/",
@ -401,9 +424,9 @@
"category": "feature",
"changes": [
"Added PDF text search to document viewer (Ctrl+F, green/amber highlights, match counter, case toggle)",
"Text layer enabled select and copy text from PDFs",
"Text layer enabled \u2014 select and copy text from PDFs",
"Added unique descriptions to all 113 UK MOD UFO documents sourced from National Archives highlights guides",
"Added Project Condign (250MB, 460pp SECRET UK EYES ONLY) the classified DI55 UAP study",
"Added Project Condign (250MB, 460pp SECRET UK EYES ONLY) \u2014 the classified DI55 UAP study",
"Downloaded US documents: Project Blue Book, CIA UFO Collection, NSA UFO Documents, Pentagon UAP Report",
"Downloaded Covert Ops: MKUltra, Stargate Program, Operation Northwoods",
"Downloaded Government: JFK Warren Commission, Pentagon Papers, CIA Torture Report",
@ -417,7 +440,7 @@
"category": "fix",
"changes": [
"Fixed dispatches post pages crashing (mood type error + fallback path)",
"SOL price ticker fixed switched to Binance API (CORS-friendly)",
"SOL price ticker fixed \u2014 switched to Binance API (CORS-friendly)",
"Tightened navbar spacing between SOL price and wallet connect",
"Converted all post mood values from integers to proper strings"
]
@ -428,19 +451,19 @@
"title": "Admin Panel Overhaul",
"category": "feature",
"changes": [
"Fixed broken Editor section full post editing with live preview",
"Fixed broken Backups section export/import site data as ZIP",
"Added SITREP admin section generate reports, view archive",
"Added Data Sync section trigger Contraband/RECON syncs, view stats",
"Added Changelog admin section CRUD for maintenance log entries",
"Added Cron Jobs section view/toggle all scheduled tasks",
"Fixed broken Editor section \u2014 full post editing with live preview",
"Fixed broken Backups section \u2014 export/import site data as ZIP",
"Added SITREP admin section \u2014 generate reports, view archive",
"Added Data Sync section \u2014 trigger Contraband/RECON syncs, view stats",
"Added Changelog admin section \u2014 CRUD for maintenance log entries",
"Added Cron Jobs section \u2014 view/toggle all scheduled tasks",
"Reorganised sidebar into grouped sections"
]
},
{
"version": "1.18.0",
"date": "06/04/2026",
"title": "SITREP Daily AI Briefing System",
"title": "SITREP \u2014 Daily AI Briefing System",
"category": "feature",
"changes": [
"Built automated daily intelligence briefing at /transmissions/sitrep",
@ -454,7 +477,7 @@
{
"version": "1.17.0",
"date": "06/04/2026",
"title": "TOKEN FORGE SPL Token Launcher",
"title": "TOKEN FORGE \u2014 SPL Token Launcher",
"category": "feature",
"changes": [
"Built token launcher at /tokenlauncher with full SPL token creation",
@ -498,7 +521,7 @@
"changes": [
"Global wallet connect button in navbar across all 28 pages",
"Multi-wallet support: Phantom, Solflare, Backpack, Coinbase, Trust, MetaMask, Jupiter",
"Persistent connection via localStorage survives page navigation",
"Persistent connection via localStorage \u2014 survives page navigation",
"Connected dropdown with address copy, Solscan link, disconnect",
"Global window.solWallet API for all Solana features",
"Refactored soldomains.js to use shared wallet (removed 146 lines)"
@ -507,7 +530,7 @@
{
"version": "1.13.0",
"date": "05/04/2026",
"title": "RADAR Live Tech News Feed",
"title": "RADAR \u2014 Live Tech News Feed",
"category": "feature",
"changes": [
"Built live tech news aggregator at /transmissions/radar",
@ -530,7 +553,7 @@
{
"version": "1.11.0",
"date": "04/04/2026",
"title": "RECON Site Restructure & Accordion Navigation",
"title": "RECON \u2014 Site Restructure & Accordion Navigation",
"category": "feature",
"changes": [
"Moved RECON to /depot/recon for consistency with other depot pages",
@ -543,7 +566,7 @@
{
"version": "1.10.0",
"date": "04/04/2026",
"title": "RECON Curated Lists Rebuild",
"title": "RECON \u2014 Curated Lists Rebuild",
"category": "feature",
"changes": [
"Flattened 4-level navigation to 2-level (sector > list > entries)",
@ -555,7 +578,7 @@
{
"version": "1.9.0",
"date": "04/04/2026",
"title": "RECON Curated Lists Database",
"title": "RECON \u2014 Curated Lists Database",
"category": "feature",
"changes": [
"Parsed 660 curated lists into 28 themed sectors",
@ -572,7 +595,7 @@
"category": "feature",
"changes": [
"Subcategories now display as 2-column card grid with expandable detail panels",
"Added weekly auto-sync resource database updates every Sunday at 03:00",
"Added weekly auto-sync \u2014 resource database updates every Sunday at 03:00",
"Click any subcategory card to expand/collapse its entries below",
"Active card highlighting with amber glow",
"Responsive grid: 2-col desktop, 1-col mobile"
@ -584,8 +607,8 @@
"title": "Sitewide Visual Overhaul",
"category": "fix",
"changes": [
"Bumped 64 font sizes sitewide no more microscopic text",
"Brightened all text colours: primary #c0c0c0→#d8d8d8, secondary #707070→#999999, muted #3a3a3a→#666666",
"Bumped 64 font sizes sitewide \u2014 no more microscopic text",
"Brightened all text colours: primary #c0c0c0\u2192#d8d8d8, secondary #707070\u2192#999999, muted #3a3a3a\u2192#666666",
"CONTRABAND page: 4-column category grid with responsive breakpoints",
"Purged all third-party attribution references from entire codebase"
]
@ -593,13 +616,13 @@
{
"version": "1.6.0",
"date": "03/04/2026",
"title": "CONTRABAND Classified Resource Index",
"title": "CONTRABAND \u2014 Classified Resource Index",
"category": "feature",
"changes": [
"Launched CONTRABAND page at /depot/contraband with 15,800+ indexed assets",
"24 categories with military codenames (CRT-001 through CRT-024)",
"Full-text search across all entries via API",
"Starred/top-pick filter system with indicators",
"Starred/top-pick filter system with \u2b50 indicators",
"Collapsible subcategories with item counts",
"Flask API endpoints: /api/contraband, /api/contraband/<slug>, /api/contraband/search"
]
@ -621,8 +644,8 @@
"title": "Globe & Chat AI Admin Panels",
"category": "feature",
"changes": [
"Admin panel: Globe management section server location, rotation speed, arc cities, colours",
"Admin panel: Chat AI configuration model selection, system prompt, greeting toggle",
"Admin panel: Globe management section \u2014 server location, rotation speed, arc cities, colours",
"Admin panel: Chat AI configuration \u2014 model selection, system prompt, greeting toggle",
"New API endpoints: /api/globe, /api/chat-config with auth-protected GET/POST",
"Interactive colour picker and slider controls for globe parameters",
"Arc cities table with add/remove functionality"

View file

@ -99,6 +99,7 @@
letter-spacing: 1px;
}
</style>
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body>
<div class="scanline-overlay"></div>
@ -200,5 +201,6 @@
<script src="/js/wallet-connect.js"></script>
<script src="/js/nav.js"></script>
<script src="/js/clock.js"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

331
css/sitewide-effects.css Normal file
View file

@ -0,0 +1,331 @@
/* =================================================
JAESWIFT Sitewide Effects CSS
================================================= */
/* 1. CRT */
html.fx-crt {
filter: contrast(1.1) saturate(1.2) brightness(0.95);
animation: fx-crt-flicker 0.15s infinite;
}
html.fx-crt body {
transform: perspective(1500px) rotateX(0.5deg);
transform-origin: center top;
background: radial-gradient(ellipse at center, #0a1a0a 0%, #000 100%);
}
@keyframes fx-crt-flicker {
0%, 98% { opacity: 1; }
99% { opacity: 0.94; }
100% { opacity: 1; }
}
.fx-crt-overlay {
position: fixed; inset: 0; pointer-events: none; z-index: 9400;
background:
repeating-linear-gradient(
to bottom,
rgba(0,0,0,0) 0px,
rgba(0,0,0,0) 2px,
rgba(0,0,0,0.18) 3px,
rgba(0,0,0,0.18) 4px
),
radial-gradient(ellipse at center, transparent 55%, rgba(0,0,0,0.7) 100%);
mix-blend-mode: multiply;
}
.fx-crt-overlay::before {
content: '';
position: absolute; inset: 0;
background: linear-gradient(90deg, rgba(255,0,0,0.03), transparent 3%, transparent 97%, rgba(0,255,255,0.03));
mix-blend-mode: screen;
}
/* 2. VHS */
html.fx-vhs body {
filter: saturate(1.4) contrast(1.1) hue-rotate(-4deg);
text-shadow: -1px 0 rgba(255,0,0,0.5), 1px 0 rgba(0,255,255,0.5);
}
.fx-vhs-roll {
position: fixed; left: 0; right: 0; height: 60px;
background: linear-gradient(180deg, transparent, rgba(255,255,255,0.09), transparent);
pointer-events: none; z-index: 9300;
animation: fx-vhs-roll 8s linear infinite;
}
@keyframes fx-vhs-roll {
0% { top: -10%; } 100% { top: 110%; }
}
.fx-vhs-glitch-block {
position: fixed; left: 0; right: 0;
background: rgba(0,255,255,0.4);
mix-blend-mode: difference;
pointer-events: none; z-index: 9310;
transform: translateX(5px);
}
/* 3. GLITCH */
html.fx-glitch body {
animation: fx-glitch-shake 3.5s infinite steps(1);
}
html.fx-glitch h1, html.fx-glitch h2, html.fx-glitch .panel-title {
position: relative;
animation: fx-glitch-chroma 2.8s infinite steps(1);
}
@keyframes fx-glitch-shake {
0%, 97%, 100% { transform: translate(0, 0); }
98% { transform: translate(2px, -1px); }
99% { transform: translate(-2px, 1px); }
}
@keyframes fx-glitch-chroma {
0%, 95%, 100% { text-shadow: none; }
96% { text-shadow: -2px 0 red, 2px 0 cyan; }
97% { text-shadow: 3px 0 lime, -3px 0 magenta; }
98% { text-shadow: -1px 0 red, 1px 0 cyan; }
}
/* 4. RED ALERT */
html.fx-redalert body {
filter: sepia(1) hue-rotate(-50deg) saturate(4) brightness(0.95);
animation: fx-redalert-pulse 1s infinite;
}
@keyframes fx-redalert-pulse {
0%, 100% { box-shadow: inset 0 0 60px 10px rgba(255,0,0,0.3); }
50% { box-shadow: inset 0 0 120px 20px rgba(255,0,0,0.7); }
}
html.fx-redalert body::after {
content: '';
position: fixed; inset: 0;
border: 8px solid transparent;
box-shadow: inset 0 0 80px 20px rgba(255,0,0,0.5);
pointer-events: none; z-index: 9400;
animation: fx-redalert-pulse 1s infinite;
}
.fx-redalert-banner {
position: fixed; top: 0; left: 0; right: 0;
background: rgba(120,0,0,0.95); color: #fff;
text-align: center; padding: 8px;
font-family: 'Orbitron', monospace; letter-spacing: 4px;
font-size: 14px; font-weight: bold;
z-index: 9700;
animation: fx-redalert-blink 0.8s infinite;
border-bottom: 2px solid #ff3333;
}
@keyframes fx-redalert-blink {
0%, 49% { opacity: 1; }
50%, 100% { opacity: 0.4; }
}
/* 5. INVERT */
html.fx-invert { filter: invert(1) hue-rotate(180deg); }
/* 6. BLUEPRINT */
html.fx-blueprint body {
filter: sepia(1) hue-rotate(180deg) saturate(3) brightness(0.9);
}
.fx-blueprint-grid {
position: fixed; inset: 0; pointer-events: none; z-index: 9050;
background-image:
linear-gradient(rgba(255,255,255,0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.1) 1px, transparent 1px);
background-size: 40px 40px;
mix-blend-mode: screen;
}
/* 7. TYPEWRITER (no special styling, just spans) */
.fx-typewriter-span { display: inline; }
/* 10. LOW GRAVITY */
html.fx-lowgrav .panel, html.fx-lowgrav .card {
transition: transform 1.2s ease-out !important;
}
.fx-lowgrav-bob {
animation: fx-lowgrav-bob 4s ease-in-out infinite;
}
@keyframes fx-lowgrav-bob {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-6px); }
}
/* 13. RAIN thunder flash */
html.fx-rain-flash body {
filter: brightness(1.3);
}
/* 15. FOG */
.fx-fog {
position: fixed; inset: 0; pointer-events: none; z-index: 9300;
background: radial-gradient(
circle 150px at var(--fx-fog-x, 50%) var(--fx-fog-y, 50%),
transparent 0%,
rgba(20,25,35,0.5) 40%,
rgba(10,15,25,0.92) 100%
);
}
/* 16. NIGHT */
html.fx-night body {
filter: brightness(0.5) contrast(1.2);
cursor: crosshair;
}
.fx-night-spot {
position: fixed; inset: 0; pointer-events: none; z-index: 9300;
background: radial-gradient(
circle 200px at var(--fx-spot-x, 50%) var(--fx-spot-y, 50%),
rgba(255,240,180,0.3) 0%,
transparent 100%
);
mix-blend-mode: screen;
}
/* 17. UNDERWATER */
html.fx-underwater body {
filter: hue-rotate(180deg) saturate(1.3) brightness(0.85);
animation: fx-underwater-sway 6s ease-in-out infinite;
}
@keyframes fx-underwater-sway {
0%, 100% { transform: skewX(0deg); }
50% { transform: skewX(0.5deg); }
}
/* 18. DIMENSIONS */
html.fx-dimensions body {
transform: perspective(1000px)
rotateX(var(--fx-tilt-x, 0deg))
rotateY(var(--fx-tilt-y, 0deg));
transition: transform 0.3s ease-out;
transform-style: preserve-3d;
}
html.fx-dimensions .panel {
transform: translateZ(20px);
transform-style: preserve-3d;
}
/* 19. PORTAL */
.fx-portal {
position: fixed;
width: 150px; height: 150px;
border-radius: 50%;
overflow: hidden;
pointer-events: none;
z-index: 9400;
border: 2px solid #00ffc8;
box-shadow:
0 0 30px rgba(0,255,200,0.6),
inset 0 0 30px rgba(0,255,200,0.4);
animation: fx-portal-ripple 1.5s ease-in-out infinite;
}
.fx-portal iframe {
width: 1200px; height: 900px;
border: 0;
pointer-events: none;
}
@keyframes fx-portal-ripple {
0%, 100% { box-shadow: 0 0 30px rgba(0,255,200,0.6), inset 0 0 30px rgba(0,255,200,0.4); }
50% { box-shadow: 0 0 60px rgba(0,255,200,0.9), inset 0 0 60px rgba(0,255,200,0.7); }
}
/* 20. RETRO */
html.retro-1995 body {
font-family: 'Comic Sans MS', 'Comic Sans', cursive !important;
background: #ffff99 !important;
color: #000 !important;
}
html.retro-1995 a { color: #0000ee !important; text-decoration: underline !important; }
html.retro-1995 a:visited { color: #551a8b !important; }
html.retro-1995 .panel {
border: 3px ridge #c0c0c0 !important;
background: #e0e0e0 !important;
color: #000 !important;
}
html.retro-1995 h1, html.retro-1995 h2, html.retro-1995 h3 {
color: #ff0066 !important;
text-shadow: 2px 2px 0 #ffff00 !important;
}
.fx-retro-1995-banner {
position: fixed; top: 0; left: 0; right: 0;
background: #ffcc00; color: #000;
text-align: center; padding: 6px;
font-family: 'Comic Sans MS', cursive;
font-weight: bold; font-size: 13px;
border-bottom: 3px ridge #ff0000;
z-index: 9700;
}
.fx-retro-1995-banner blink {
animation: fx-blink 1s steps(2) infinite;
}
@keyframes fx-blink { to { visibility: hidden; } }
html.retro-2005 body {
background: linear-gradient(180deg, #cfe8ff 0%, #9dc5f0 100%) !important;
font-family: 'Trebuchet MS', 'Verdana', sans-serif !important;
}
html.retro-2005 .panel {
background: linear-gradient(180deg, #ffffff 0%, #d6e8ff 100%) !important;
border: 1px solid #4a90d9 !important;
border-radius: 12px !important;
box-shadow: 0 4px 12px rgba(74,144,217,0.3), inset 0 1px 0 #fff !important;
color: #0a3a6a !important;
}
html.retro-2005 h1, html.retro-2005 h2 {
background: linear-gradient(180deg, #1a5eae, #0a3a6a) !important;
-webkit-background-clip: text !important;
background-clip: text !important;
color: transparent !important;
text-shadow: none !important;
}
html.retro-2015 body {
background: #fafafa !important;
color: #212121 !important;
font-family: 'Roboto', 'Arial', sans-serif !important;
}
html.retro-2015 .panel {
background: #fff !important;
border: none !important;
border-radius: 4px !important;
box-shadow: 0 2px 4px rgba(0,0,0,0.1), 0 4px 12px rgba(0,0,0,0.08) !important;
color: #212121 !important;
}
html.retro-2015 h1 { color: #ff5722 !important; font-weight: 300 !important; }
html.retro-2015 h2 { color: #2196f3 !important; font-weight: 300 !important; }
html.retro-2015 a { color: #2196f3 !important; }
/* 21. PARTY */
html.fx-party body {
animation: fx-party-hue 2s linear infinite;
}
@keyframes fx-party-hue {
0% { filter: hue-rotate(0deg); }
100% { filter: hue-rotate(360deg); }
}
/* 22. GHOST */
html.fx-ghost * {
cursor: none !important;
}
html.fx-ghost body,
html.fx-ghost .panel,
html.fx-ghost a,
html.fx-ghost button,
html.fx-ghost h1, html.fx-ghost h2, html.fx-ghost h3, html.fx-ghost p, html.fx-ghost span {
transition: opacity 0.3s;
}
html.fx-ghost .panel,
html.fx-ghost h1, html.fx-ghost h2, html.fx-ghost h3,
html.fx-ghost p, html.fx-ghost a, html.fx-ghost button, html.fx-ghost li {
opacity: 0.08;
}
html.fx-ghost .panel:hover,
html.fx-ghost h1:hover, html.fx-ghost h2:hover, html.fx-ghost h3:hover,
html.fx-ghost p:hover, html.fx-ghost a:hover, html.fx-ghost button:hover, html.fx-ghost li:hover {
opacity: 1;
}
/* 25. HACKER */
html.fx-hacker body > *:not(canvas):not(script):not(style) {
filter: brightness(0.25);
}
/* Reduced motion: neutralize heavy animations */
@media (prefers-reduced-motion: reduce) {
html.fx-crt, html.fx-redalert body, html.fx-party body,
.fx-vhs-roll, .fx-redalert-banner {
animation: none !important;
}
}

View file

@ -10,6 +10,7 @@
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/section.css">
<link rel="stylesheet" href="/css/contraband.css">
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body>
<div class="scanline-overlay"></div>
@ -66,5 +67,6 @@
<script src="/js/nav.js"></script>
<script src="/js/clock.js"></script>
<script src="/js/contraband.js"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

View file

@ -9,6 +9,7 @@
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/section.css">
<link rel="stylesheet" href="/css/contraband.css?v=20260404">
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body style="background:#0a0a0c;">
<div class="scanline-overlay"></div>
@ -63,5 +64,6 @@
<script src="/js/nav.js"></script>
<script src="/js/clock.js"></script>
<script src="/js/awesomelist.js?v=20260404"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

View file

@ -8,6 +8,7 @@
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/section.css">
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body>
<div class="scanline-overlay"></div>
@ -66,5 +67,6 @@
<script src="/js/wallet-connect.js"></script>
<script src="/js/nav.js"></script>
<script src="/js/clock.js"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

View file

@ -8,6 +8,7 @@
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/section.css">
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body>
<div class="scanline-overlay"></div>
@ -78,5 +79,6 @@
<script src="/js/wallet-connect.js"></script>
<script src="/js/nav.js"></script>
<script src="/js/clock.js"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

View file

@ -12,6 +12,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&family=Orbitron:wght@400;500;600;700;800;900&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body class="section-page">
@ -112,5 +113,6 @@
<script src="/js/main.js"></script>
<script src="/js/nav.js"></script>
<script src="/js/leaderboards.js"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

View file

@ -9,6 +9,7 @@
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/section.css">
<link rel="stylesheet" href="/css/changelog.css">
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body>
<div class="scanline-overlay"></div>
@ -53,5 +54,6 @@
<script src="/js/nav.js"></script>
<script src="/js/clock.js"></script>
<script src="/js/changelog.js"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

View file

@ -8,6 +8,7 @@
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/section.css">
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body>
<div class="scanline-overlay"></div>
@ -66,5 +67,6 @@
<script src="/js/wallet-connect.js"></script>
<script src="/js/nav.js"></script>
<script src="/js/clock.js"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

View file

@ -9,6 +9,7 @@
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/section.css">
<link rel="stylesheet" href="/css/telemetry.css">
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body>
<div class="scanline-overlay"></div>
@ -226,5 +227,6 @@
<script src="/js/nav.js"></script>
<script src="/js/clock.js"></script>
<script src="/js/telemetry.js"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

View file

@ -12,6 +12,7 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&family=Orbitron:wght@400;500;600;700;800;900&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<script src="https://unpkg.com/globe.gl@2.45.1/dist/globe.gl.min.js"></script>
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body>
<!-- Scanline overlay -->
@ -597,5 +598,6 @@
<script src="/js/globe.js"></script>
<script src="/js/processes.js"></script>
<script src="/js/clock.js"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

View file

@ -10,7 +10,6 @@
const HIST_KEY = 'jaeCliHist';
let cmdHistory = [];
let devMode = false;
let matrixActive = false;
let sessionCmdCount = 0;
let sessionPerCmd = {};
let mode = null; // null | 'ssh' | 'adventure' | 'ttyper'
@ -190,6 +189,15 @@
' /adventure cyberpunk text adventure',
' /ttyper typing speed test',
'',
'— EFFECTS (sitewide visual overlays) —',
' /crt /vhs /glitch /redalert /invert /blueprint /typewriter',
' /gravity /earthquake /lowgravity /melt /shuffle',
' /rain /snow /fog /night /underwater',
' /dimensions /portal /retro <1995|2005|2015|now>',
' /partymode /ghostmode /quantum /sneak /hacker',
' /matrix /cmatrix matrix rain overlays',
' /effects show active · /effects off · /effects all (chaos)',
'',
'— STATS —',
' /achievements your unlocked commands',
' /leaderboard session & all-time stats',
@ -334,11 +342,10 @@
};
commands.matrix = function () {
matrixActive = !matrixActive;
toggleMatrix(matrixActive);
return matrixActive
? 'Matrix rain enabled. Follow the white rabbit.'
: 'Matrix rain disabled. Back to the desert of the real.';
if (!window.__jaeEffects) return 'effects module not loaded.';
const on = window.__jaeEffects.toggle('matrix');
return on ? 'Matrix rain enabled. Follow the white rabbit.'
: 'Matrix rain disabled. Back to the desert of the real.';
};
commands.clear = function () {
@ -837,79 +844,100 @@
].filter(Boolean));
}
// ─── /cmatrix — enhanced matrix rain ─────────────
let cmatrixCanvas = null, cmatrixRAF = null, cmatrixAudio = null, cmatrixStart = 0;
function toggleCMatrix(on) {
if (on) {
cmatrixCanvas = document.createElement('canvas');
cmatrixCanvas.id = 'cmatrixRain';
Object.assign(cmatrixCanvas.style, {
position: 'fixed', inset: '0', width: '100%', height: '100%',
pointerEvents: 'none', zIndex: '8', opacity: '0.32',
});
document.body.appendChild(cmatrixCanvas);
const ctx = cmatrixCanvas.getContext('2d');
function resize() { cmatrixCanvas.width = innerWidth; cmatrixCanvas.height = innerHeight; }
resize();
window.addEventListener('resize', resize);
const chars = 'アイウエオカキクケコサシスセソタチツテトナニヌネ01JAESWIFT░▒▓█'.split('');
const size = 14;
const cols = Math.floor(cmatrixCanvas.width / size);
const drops = new Array(cols).fill(0).map(() => Math.random() * 40);
cmatrixStart = Date.now();
try {
const AC = window.AudioContext || window.webkitAudioContext;
if (AC) cmatrixAudio = new AC();
} catch (e) {}
let tick = 0;
function draw() {
const t = (Date.now() - cmatrixStart) / 1000;
const phase = (t % 30) / 30;
const speed = 1 + phase * 2.5;
ctx.fillStyle = 'rgba(0, 0, 0, 0.08)';
ctx.fillRect(0, 0, cmatrixCanvas.width, cmatrixCanvas.height);
ctx.font = size + 'px JetBrains Mono, monospace';
for (let i = 0; i < drops.length; i++) {
const ch = chars[Math.floor(Math.random() * chars.length)];
ctx.fillStyle = (i % 2 === 0) ? '#00ff66' : '#33ddff';
ctx.fillText(ch, i * size, drops[i] * size);
if (drops[i] * size > cmatrixCanvas.height && Math.random() > 0.97) drops[i] = 0;
drops[i] += speed;
}
tick++;
if (cmatrixAudio && tick % 4 === 0) {
try {
const osc = cmatrixAudio.createOscillator();
const g = cmatrixAudio.createGain();
osc.type = 'square';
osc.frequency.value = 1600 + Math.random() * 800;
g.gain.value = 0.0035;
osc.connect(g); g.connect(cmatrixAudio.destination);
osc.start();
osc.stop(cmatrixAudio.currentTime + 0.02);
} catch (e) {}
}
cmatrixRAF = requestAnimationFrame(draw);
}
draw();
} else {
if (cmatrixRAF) cancelAnimationFrame(cmatrixRAF);
if (cmatrixCanvas) cmatrixCanvas.remove();
if (cmatrixAudio) { try { cmatrixAudio.close(); } catch(e){} }
cmatrixCanvas = null; cmatrixAudio = null;
}
}
let cmatrixActive = false;
// ─── /cmatrix — migrated to sitewide-effects.js ──
commands.cmatrix = function () {
cmatrixActive = !cmatrixActive;
toggleCMatrix(cmatrixActive);
return cmatrixActive
? 'CMATRIX engaged. Dual-colour rain with audio. Toggle off with /cmatrix.'
: 'CMATRIX disengaged.';
if (!window.__jaeEffects) return 'effects module not loaded.';
const on = window.__jaeEffects.toggle('cmatrix');
return on ? 'CMATRIX engaged. Dual-colour rain with audio. Toggle off with /cmatrix.'
: 'CMATRIX disengaged.';
};
// ─── EFFECTS SUITE — thin wrappers over window.__jaeEffects ──
function fx(name, onMsg, offMsg) {
return function () {
if (!window.__jaeEffects) return 'effects module not loaded.';
const on = window.__jaeEffects.toggle(name);
return on ? onMsg : offMsg;
};
}
commands.crt = fx('crt', 'CRT mode engaged. [VINTAGE BEAM ONLINE]', 'CRT mode disengaged.');
commands.vhs = fx('vhs', 'VHS tape loaded. Tracking...', 'VHS ejected.');
commands.glitch = fx('glitch', 'Reality corrupted. Good luck.', 'Reality stabilised.');
commands.redalert = fx('redalert', '⚠ DEFCON 1. Battle stations. ⚠', 'Red alert stood down.');
commands.red = commands.redalert;
commands.invert = fx('invert', 'Polarity inverted.', 'Polarity restored.');
commands.blueprint = fx('blueprint', 'Blueprint mode. Architect vision enabled.', 'Blueprint mode disabled.');
commands.typewriter = fx('typewriter', 'Typewriter engaged. Retyping...', 'Typewriter reset.');
commands.gravity = fx('gravity', '🌍 Gravity enabled. Everything falls.', '🌍 Gravity disabled. Restored.');
commands.earthquake = fx('earthquake', '🌋 7.5 magnitude — hold on (10s).', '🌋 Earthquake over.');
commands.lowgravity = fx('lowgravity', '🚀 Low-gravity environment active.', '🚀 Gravity normalised.');
commands.melt = fx('melt', 'Pixels liquifying...', 'Reformed.');
commands.shuffle = fx('shuffle', 'Words scrambled.', 'Words restored.');
commands.rain = fx('rain', '🌧️ Rain enabled. Manchester vibes.', '🌧️ Rain stopped.');
commands.snow = fx('snow', '❄️ Snow enabled. Winter is here.', '❄️ Thaw complete.');
commands.fog = fx('fog', '🌫️ Fog of war. Mind the torchlight.', '🌫️ Fog lifted.');
commands.night = fx('night', '🌙 Night-vision enabled. Spotlight tracking cursor.', '🌙 Dawn.');
commands.underwater = fx('underwater', '🌊 Submerged. Pressure nominal.', '🌊 Surfaced.');
commands.dimensions = fx('dimensions', '🔺 3D tilt engaged. Follow the cursor.', '🔺 2D restored.');
commands.portal = fx('portal', '🌀 Portal opened. Cursor is now a window.', '🌀 Portal closed.');
commands.partymode = fx('partymode', '🎉 PARTY MODE. Can someone get the disco ball?', '🎉 Party over. Clean-up on aisle 4.');
commands.ghostmode = fx('ghostmode', '👻 Ghost mode. Only the brave shall see.', '👻 Visible again.');
commands.quantum = fx('quantum', '⚛️ Quantum uncertainty enabled. Panels teleporting.', '⚛️ Observation collapsed. Panels reset.');
commands.sneak = fx('sneak', 'All labels redacted. █████.', 'Labels restored.');
commands.hacker = fx('hacker', 'H4X0R M0D3 3NG4G3D. We are in.', 'Exited.');
commands.retro = function (args) {
if (!window.__jaeEffects) return 'effects module not loaded.';
const year = (args[0] || '').toLowerCase();
const fx = window.__jaeEffects.registry.retro;
if (!year || year === 'now' || year === 'off') {
fx.disable();
return 'Retro mode disabled. Welcome back to 2026.';
}
if (!['1995','2005','2015'].includes(year)) {
return 'usage: /retro <1995|2005|2015|now>';
}
fx.disable();
fx.enable(year);
const flavour = {
'1995': 'Welcome to the World Wide Web! 🌐 Best viewed in Netscape Navigator.',
'2005': 'Web 2.0, baby. Glossy gradients incoming.',
'2015': 'Material Design. Clean. Flat. Safe.',
};
return flavour[year];
};
commands.effects = function (args) {
if (!window.__jaeEffects) return 'effects module not loaded.';
const sub = (args[0] || '').toLowerCase();
if (sub === 'off') {
const n = window.__jaeEffects.active().length;
window.__jaeEffects.disableAll();
return `Disabled ${n} effect(s).`;
}
if (sub === 'all') {
const list = window.__jaeEffects.list().filter(n => n !== 'retro');
list.forEach(n => { try { window.__jaeEffects.enable(n); } catch(e){} });
return '⚠ CHAOS MODE. ' + list.length + ' effects enabled simultaneously. RIP your CPU.';
}
const active = window.__jaeEffects.active();
if (!active.length) return 'No effects currently active. Try /help for the EFFECTS list.';
const lines = [
'═══ ACTIVE EFFECTS ═══',
'┌─────────────────────┬────────┐',
'│ NAME │ STATUS │',
'├─────────────────────┼────────┤',
];
active.forEach(n => {
lines.push('│ ' + n.padEnd(20) + '│ ACTIVE │');
});
lines.push('└─────────────────────┴────────┘');
lines.push(`Total: ${active.length} · /effects off to disable all`);
return lines.join('\n');
};
// ─── /achievements ───────────────────────────────
const TOTAL_COMMANDS = 24;
const TOTAL_COMMANDS = 50;
commands.achievements = function () {
const unlocked = [...achievements].sort();
const n = unlocked.length;
@ -964,49 +992,8 @@
]);
};
// ─── Matrix rain overlay ─────────────────────────
let matrixCanvas = null;
let matrixRAF = null;
function toggleMatrix(on) {
if (on) {
matrixCanvas = document.createElement('canvas');
matrixCanvas.id = 'matrixRain';
Object.assign(matrixCanvas.style, {
position: 'fixed', inset: '0', width: '100%', height: '100%',
pointerEvents: 'none', zIndex: '7', opacity: '0.18',
});
document.body.appendChild(matrixCanvas);
const ctx = matrixCanvas.getContext('2d');
function resize() {
matrixCanvas.width = window.innerWidth;
matrixCanvas.height = window.innerHeight;
}
resize();
window.addEventListener('resize', resize);
const chars = 'アイウエオカキクケコサシスセソタチツテトナニヌネ01JAESWIFT'.split('');
const size = 16;
const cols = Math.floor(matrixCanvas.width / size);
const drops = new Array(cols).fill(1);
function draw() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.06)';
ctx.fillRect(0, 0, matrixCanvas.width, matrixCanvas.height);
ctx.fillStyle = '#00cc33';
ctx.font = size + 'px JetBrains Mono, monospace';
for (let i = 0; i < drops.length; i++) {
const ch = chars[Math.floor(Math.random() * chars.length)];
ctx.fillText(ch, i * size, drops[i] * size);
if (drops[i] * size > matrixCanvas.height && Math.random() > 0.975) drops[i] = 0;
drops[i]++;
}
matrixRAF = requestAnimationFrame(draw);
}
draw();
} else {
if (matrixRAF) cancelAnimationFrame(matrixRAF);
if (matrixCanvas) matrixCanvas.remove();
matrixCanvas = null;
}
}
// ─── Matrix rain migrated to sitewide-effects.js ──
// ─── Konami Code → Developer Mode ────────────────
const KONAMI = ['ArrowUp','ArrowUp','ArrowDown','ArrowDown','ArrowLeft','ArrowRight','ArrowLeft','ArrowRight','b','a'];
@ -1096,8 +1083,7 @@
// ─── Boss key — Escape / Ctrl+Shift+B ────────────
function bossKeyActivate() {
try {
if (matrixActive) { matrixActive = false; toggleMatrix(false); }
if (cmatrixActive) { cmatrixActive = false; toggleCMatrix(false); }
if (window.__jaeEffects) { try { window.__jaeEffects.disableAll(); } catch(e){} }
const badge = document.getElementById('devModeBadge');
if (badge) badge.style.display = 'none';
const toasts = document.querySelectorAll('.jae-cli-toast');
@ -1123,7 +1109,8 @@
const isCtrlShiftB = (e.ctrlKey && e.shiftKey && (e.key === 'B' || e.key === 'b'));
if (isEsc || isCtrlShiftB) {
// Don't nuke on Escape while user is typing in chat unless something is actually "hot"
const hot = matrixActive || cmatrixActive || document.getElementById('devModeBadge') || document.querySelector('.jae-cli-toast');
const anyFx = window.__jaeEffects && window.__jaeEffects.active().length > 0;
const hot = anyFx || document.getElementById('devModeBadge') || document.querySelector('.jae-cli-toast');
if (isCtrlShiftB || (isEsc && hot)) {
bossKeyActivate();
if (isCtrlShiftB) e.preventDefault();

1143
js/sitewide-effects.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -4,8 +4,10 @@
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0;url=/depot/recon">
<title>Redirecting to RECON...</title>
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body style="background:#0a0a0c;">
<p>Redirecting to <a href="/depot/recon">RECON</a>...</p>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>

View file

@ -10,6 +10,7 @@
<link rel="stylesheet" href="/css/section.css">
<link rel="stylesheet" href="/css/radar.css?v=20260415">
<style>body{background:#0a0a0a;}</style>
<link rel="stylesheet" href="/css/sitewide-effects.css">
</head>
<body>
<div class="scanline-overlay"></div>
@ -139,5 +140,6 @@
<script src="/js/nav.js"></script>
<script src="/js/clock.js"></script>
<script src="/js/radar.js?v=20260415"></script>
<script src="/js/sitewide-effects.js" defer></script>
</body>
</html>