<html class="scroll-smooth" lang="en">
| <head>
| <meta charset="utf-8"/>
| <meta content="width=device-width, initial-scale=1" name="viewport"/>
| <title>
| Smart Sphere Star Harnessing App
| </title>
| <script src="
https://cdn.tailwindcss.com">
| </script>
| <link href="
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet"/>
| <link href="
https://fonts.googleapis.com/css2?family=Orbitron&family=Roboto+Mono&display=swap" rel="stylesheet"/>
| <style>
| body {
| font-family: 'Roboto Mono', monospace;
| background-color: #0f172a;
| color: #d1d5db;
| }
| .terminal {
| background-color: #111827;
| border-radius: 0.5rem;
| box-shadow: 0 0 15px #22c55e;
| font-family: 'Roboto Mono', monospace;
| font-size: 0.875rem;
| line-height: 1.25rem;
| color: #22c55e;
| padding: 1rem;
| min-height: 300px;
| overflow-y: auto;
| white-space: pre-wrap;
| user-select: text;
| }
| .terminal-input {
| outline: none;
| border: none;
| background: transparent;
| color: #22c55e;
| font-family: 'Roboto Mono', monospace;
| font-size: 0.875rem;
| width: 100%;
| caret-color: #22c55e;
| }
| .scrollbar-thin::-webkit-scrollbar {
| width: 6px;
| }
| .scrollbar-thin::-webkit-scrollbar-track {
| background: transparent;
| }
| .scrollbar-thin::-webkit-scrollbar-thumb {
| background-color: #22c55e;
| border-radius: 3px;
| }
| .star-filled-vial {
| width: 48px;
| height: 96px;
| background: linear-gradient(180deg, #22c55e 0%, #166534 100%);
| border-radius: 0.75rem 0.75rem 0.25rem 0.25rem;
| box-shadow: 0 0 8px #22c55e;
| position: relative;
| margin: 0.25rem;
| display: flex;
| flex-direction: column;
| justify-content: flex-end;
| overflow: hidden;
| cursor: grab;
| transition: transform 0.3s ease;
| }
| .star-filled-vial:active {
| cursor: grabbing;
| transform: scale(1.1);
| box-shadow: 0 0 20px #4ade80;
| z-index: 1000;
| }
| .star-filled-vial:hover {
| transform: scale(1.1);
| box-shadow: 0 0 15px #4ade80;
| z-index: 10;
| }
| .star-filled-vial::before {
| content: '';
| position: absolute;
| top: 0.25rem;
| left: 50%;
| transform: translateX(-50%);
| width: 24px;
| height: 12px;
| background: #166534;
| border-radius: 12px 12px 0 0;
| box-shadow: inset 0 2px 4px #22c55e;
| z-index: 10;
| }
| .vial-liquid {
| background: #22c55e;
| height: 60%;
| border-radius: 0 0 0.75rem 0.75rem;
| box-shadow: inset 0 0 10px #4ade80;
| transition: height 0.5s ease;
| }
| .btn-green {
| background-color: #22c55e;
| color: #0f172a;
| font-weight: 600;
| transition: background-color 0.3s ease;
| }
| .btn-green:hover:not(:disabled) {
| background-color: #16a34a;
| }
| .btn-green:disabled {
| background-color: #4ade80;
| cursor: not-allowed;
| }
| .btn-red {
| background-color: #dc2626;
| color: #fef2f2;
| font-weight: 600;
| transition: background-color 0.3s ease;
| }
| .btn-red:hover:not(:disabled) {
| background-color: #b91c1c;
| }
| .btn-red:disabled {
| background-color: #fca5a5;
| cursor: not-allowed;
| }
| .btn-yellow {
| background-color: #eab308;
| color: #1e293b;
| font-weight: 600;
| transition: background-color 0.3s ease;
| }
| .btn-yellow:hover {
| background-color: #ca8a04;
| }
| .scrollbar-thin {
| scrollbar-width: thin;
| scrollbar-color: #22c55e transparent;
| }
| /* Sphere container and beams animation */
| .sphere-container {
| position: relative;
| width: 100%;
| max-width: 400px;
| aspect-ratio: 1 / 1;
| margin: 0 auto;
| perspective: 1200px;
| }
| .sphere {
| width: 100%;
| height: 100%;
| border-radius: 50%;
| background: radial-gradient(circle at center, #22c55e 20%, #064e3b 90%);
| box-shadow:
| inset 0 0 20px #4ade80,
| 0 0 30px #22c55e;
| position: relative;
| transform-style: preserve-3d;
| animation: sphere-rotate 20s linear infinite;
| }
| @keyframes sphere-rotate {
| 0% {
| transform: rotateX(0deg) rotateY(0deg);
| }
| 100% {
| transform: rotateX(360deg) rotateY(360deg);
| }
| }
| /* Beams container */
| .beams-container {
| position: absolute;
| top: 50%;
| left: 50%;
| width: 100%;
| height: 100%;
| pointer-events: none;
| transform-style: preserve-3d;
| transform-origin: center center;
| animation: beams-pulse 3s ease-in-out infinite;
| }
| @keyframes beams-pulse {
| 0%, 100% {
| filter: drop-shadow(0 0 6px #22c55e);
| }
| 50% {
| filter: drop-shadow(0 0 12px #4ade80);
| }
| }
| /* Beam line */
| .beam-line {
| position: absolute;
| width: 2px;
| background: linear-gradient(180deg, #22c55e, transparent);
| border-radius: 1px;
| transform-origin: top center;
| animation: beam-glow 2s ease-in-out infinite alternate;
| filter: drop-shadow(0 0 4px #22c55e);
| }
| @keyframes beam-glow {
| 0% {
| opacity: 0.6;
| box-shadow: 0 0 6px #22c55e;
| }
| 100% {
| opacity: 1;
| box-shadow: 0 0 14px #4ade80;
| }
| }
| /* Star dot */
| .star-dot {
| position: absolute;
| width: 12px;
| height: 12px;
| background: #22c55e;
| border-radius: 50%;
| box-shadow: 0 0 8px #4ade80;
| cursor: pointer;
| transition: transform 0.3s ease;
| }
| .star-dot:hover {
| transform: scale(1.5);
| box-shadow: 0 0 20px #86efac;
| z-index: 20;
| }
| /* Voice & Brain info box */
| .info-box {
| background: #064e3b;
| border: 2px solid #22c55e;
| border-radius: 0.5rem;
| padding: 1rem;
| margin-top: 1rem;
| color: #a7f3d0;
| font-size: 0.9rem;
| font-family: 'Roboto Mono', monospace;
| user-select: none;
| }
| /* Voice icon animation */
| .voice-icon {
| animation: pulse-voice 2s infinite;
| color: #22c55e;
| font-size: 1.5rem;
| vertical-align: middle;
| margin-right: 0.5rem;
| }
| @keyframes pulse-voice {
| 0%, 100% {
| opacity: 1;
| text-shadow: 0 0 6px #22c55e;
| }
| 50% {
| opacity: 0.6;
| text-shadow: 0 0 12px #4ade80;
| }
| }
| /* Brain icon animation */
| .brain-icon {
| animation: pulse-brain 3s infinite;
| color: #22c55e;
| font-size: 1.5rem;
| vertical-align: middle;
| margin-right: 0.5rem;
| }
| @keyframes pulse-brain {
| 0%, 100% {
| opacity: 1;
| text-shadow: 0 0 6px #22c55e;
| }
| 50% {
| opacity: 0.7;
| text-shadow: 0 0 14px #4ade80;
| }
| }
| /* Scrollable star list with custom scrollbar */
| .star-list {
| max-height: 180px;
| overflow-y: auto;
| scrollbar-width: thin;
| scrollbar-color: #22c55e transparent;
| }
| .star-list::-webkit-scrollbar {
| width: 6px;
| }
| .star-list::-webkit-scrollbar-track {
| background: transparent;
| }
| .star-list::-webkit-scrollbar-thumb {
| background-color: #22c55e;
| border-radius: 3px;
| }
| /* Tooltip for star dots */
| .tooltip {
| position: absolute;
| background: #064e3b;
| border: 1px solid #22c55e;
| padding: 0.25rem 0.5rem;
| border-radius: 0.25rem;
| font-size: 0.75rem;
| color: #a7f3d0;
| pointer-events: none;
| white-space: nowrap;
| user-select: none;
| z-index: 50;
| opacity: 0;
| transition: opacity 0.2s ease;
| }
| .tooltip.visible {
| opacity: 1;
| }
| /* Drag & Drop container styles */
| #vials-container, #distribution-container {
| min-height: 120px;
| border: 2px dashed #22c55e;
| border-radius: 0.5rem;
| padding: 0.5rem;
| display: flex;
| flex-wrap: wrap;
| gap: 0.5rem;
| background-color: #0f172a;
| transition: background-color 0.3s ease;
| }
| #vials-container.dragover, #distribution-container.dragover {
| background-color: #164e2e;
| border-color: #4ade80;
| }
| /* Distribution section */
| #distribution-section {
| background-color: #111827;
| border-radius: 0.75rem;
| padding: 1rem;
| margin-top: 1rem;
| color: #a7f3d0;
| font-family: 'Roboto Mono', monospace;
| }
| #distribution-section h3 {
| font-family: 'Orbitron', monospace;
| color: #22c55e;
| margin-bottom: 0.5rem;
| }
| /* Timezone grid */
| #timezone-grid {
| display: grid;
| grid-template-columns: repeat(auto-fill,minmax(120px,1fr));
| gap: 0.5rem;
| max-height: 300px;
| overflow-y: auto;
| border: 1px solid #22c55e;
| border-radius: 0.5rem;
| padding: 0.5rem;
| background-color: #0f172a;
| }
| .timezone-block {
| background-color: #064e3b;
| border: 1px solid #22c55e;
| border-radius: 0.5rem;
| padding: 0.5rem;
| font-size: 0.75rem;
| text-align: center;
| user-select: none;
| cursor: default;
| color: #a7f3d0;
| display: flex;
| flex-direction: column;
| justify-content: center;
| align-items: center;
| min-height: 60px;
| transition: background-color 0.3s ease;
| }
| .timezone-block.active {
| background-color: #22c55e;
| color: #0f172a;
| font-weight: 700;
| box-shadow: 0 0 10px #4ade80;
| }
| /* Responsive tweaks */
| @media (max-width: 768px) {
| main {
| grid-template-columns: 1fr !important;
| }
| #distribution-section {
| margin-top: 1.5rem;
| }
| }
| </style>
| </head>
| <body class="min-h-screen flex flex-col">
| <header class="bg-gray-900 p-4 flex flex-col md:flex-row items-center justify-between">
| <div class="flex items-center space-x-3">
| <img alt="Smart tracking sphere, metallic silver with green glowing lines, floating in space" class="w-12 h-12 rounded-full" src="
https://placehold.co/48x48/png?text=Sphere"/>
| <h1 class="text-2xl font-orbitron font-bold text-green-400 select-none">
| Smart Sphere Star Harnessing
| </h1>
| </div>
| <nav class="mt-3 md:mt-0">
| <ul class="flex space-x-6 text-green-300 font-semibold text-sm select-none">
| <li>
| <button aria-label="Start harnessing process" class="btn-green px-3 py-1 rounded flex items-center space-x-2" id="btn-start">
| <i aria-hidden="true" class="fas fa-play">
| </i>
| <span>
| Start Harness
| </span>
| </button>
| </li>
| <li>
| <button aria-label="Stop harnessing process" class="btn-red px-3 py-1 rounded flex items-center space-x-2" disabled="" id="btn-stop">
| <i aria-hidden="true" class="fas fa-stop">
| </i>
| <span>
| Stop Harness
| </span>
| </button>
| </li>
| </ul>
| </nav>
| </header>
| <main class="flex-grow p-4 max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-4 gap-6">
| <!-- Sphere & Beams Section -->
| <section class="col-span-1 md:col-span-2 bg-gray-800 rounded-lg p-4 flex flex-col items-center relative">
| <div aria-label="Smart sphere with tracking beams" class="sphere-container">
| <div class="sphere" id="sphere">
| </div>
| <div aria-hidden="true" class="beams-container" id="beams-container">
| </div>
| <div aria-hidden="true" class="tooltip" id="tooltip" role="tooltip">
| </div>
| </div>
| <p class="mt-4 text-green-300 text-center font-mono text-sm max-w-xl">
| The sphere intelligently tracks stars and harnesses their energy by searching constellations and individual stars. Click on stars to see details.
| </p>
| <div aria-atomic="true" aria-live="polite" class="info-box mt-6 w-full max-w-xl" id="voice-brain-info">
| <div class="flex items-center mb-2">
| <i aria-hidden="true" class="fas fa-microphone voice-icon">
| </i>
| <span>
| <strong>
| Voice Enabled:
| </strong>
| The sphere can communicate with stars using voice commands.
| </span>
| </div>
| <div class="flex items-center">
| <i aria-hidden="true" class="fas fa-brain brain-icon">
| </i>
| <span>
| <strong>
| Brain Insurance:
| </strong>
| Only
| <em>
| Antonio Rodriguez Jr.
| </em>
| can convert, channel, stream, listen, touch, smell, feel, and manage star energy.
| </span>
| </div>
| </div>
| </section>
| <!-- Star List & Vials Section -->
| <section class="col-span-1 md:col-span-2 bg-gray-900 rounded-lg p-4 flex flex-col">
| <h2 class="text-green-400 font-orbitron text-xl mb-3 select-none">
| Stars Harnessed & To Harness
| </h2>
| <div class="flex flex-col space-y-4 overflow-y-auto max-h-[400px] scrollbar-thin pr-2">
| <div>
| <h3 class="text-green-300 font-semibold mb-1">
| Harnessed Stars
| </h3>
| <ul aria-label="List of harnessed stars" class="list-disc list-inside text-green-200 star-list" id="list-harnessed" tabindex="0">
| </ul>
| </div>
| <div>
| <h3 class="text-yellow-400 font-semibold mb-1">
| Stars To Harness
| </h3>
| <ul aria-label="List of stars to harness" class="list-disc list-inside text-yellow-300 star-list" id="list-to-harness" tabindex="0">
| </ul>
| </div>
| </div>
| <h2 class="text-green-400 font-orbitron text-xl mt-6 mb-3 select-none">
| Collected Vials (Drag to Distribute Energy)
| </h2>
| <div aria-dropeffect="move" aria-label="Collected energy vials" class="flex flex-wrap gap-2 min-h-[120px]" id="vials-container" tabindex="0">
| </div>
| <section aria-label="Energy distribution section" id="distribution-section" tabindex="0">
| <h3>
| Energy Distribution Across Timezones
| </h3>
| <p class="mb-2 text-sm text-green-300">
| Drag vials here to distribute star energy to real-life locations worldwide using IP blocks and timezone coverage. All timezones are included to ensure universal interest reception.
| </p>
| <div aria-dropeffect="move" aria-label="Distributed energy vials container" class="min-h-[120px] flex flex-wrap gap-2" id="distribution-container" tabindex="0">
| </div>
| <h3 class="mt-4">
| Timezones
| </h3>
| <div aria-label="List of all world timezones with energy distribution status" id="timezone-grid" tabindex="0">
| </div>
| </section>
| </section>
| </main>
| <!-- Terminal Section -->
| <section class="bg-gray-900 p-4 max-w-7xl mx-auto rounded-lg mt-6 mb-6">
| <h2 class="text-green-400 font-orbitron text-xl mb-3 select-none">
| Star Communication Terminal
| </h2>
| <div aria-atomic="true" aria-label="Star communication terminal" aria-live="polite" aria-multiline="true" class="terminal scrollbar-thin" contenteditable="false" id="terminal" role="textbox" tabindex="0">
| <div aria-atomic="true" aria-live="polite" class="mb-2" id="terminal-output">
| </div>
| <div class="flex items-center space-x-2">
| <span aria-hidden="true" class="text-green-400 font-bold select-none">
| >
| </span>
| <input aria-label="Terminal command input" autocomplete="off" class="terminal-input flex-grow" disabled="" id="terminal-input" spellcheck="false" type="text"/>
| </div>
| </div>
| </section>
| <script>
| // Data for stars with 3D positions (x,y in % relative to sphere container)
| const allStars = [
| { name: "Sirius", constellation: "Canis Major", harnessed: true, x: 70, y: 30, voice: true, brain: true },
| { name: "Betelgeuse", constellation: "Orion", harnessed: true, x: 40, y: 20, voice: true, brain: false },
| { name: "Rigel", constellation: "Orion", harnessed: false, x: 45, y: 60, voice: false, brain: false },
| { name: "Vega", constellation: "Lyra", harnessed: false, x: 80, y: 50, voice: false, brain: false },
| { name: "Polaris", constellation: "Ursa Minor", harnessed: true, x: 50, y: 10, voice: true, brain: true },
| { name: "Altair", constellation: "Aquila", harnessed: false, x: 60, y: 70, voice: false, brain: false },
| { name: "Aldebaran", constellation: "Taurus", harnessed: false, x: 30, y: 40, voice: false, brain: false },
| { name: "Antares", constellation: "Scorpius", harnessed: false, x: 20, y: 65, voice: false, brain: false },
| { name: "Spica", constellation: "Virgo", harnessed: true, x: 35, y: 25, voice: true, brain: false },
| { name: "Deneb", constellation: "Cygnus", harnessed: false, x: 75, y: 75, voice: false, brain: false },
| { name: "Castor", constellation: "Gemini", harnessed: false, x: 55, y: 35, voice: false, brain: false },
| { name: "Pollux", constellation: "Gemini", harnessed: false, x: 58, y: 38, voice: false, brain: false },
| { name: "Procyon", constellation: "Canis Minor", harnessed: true, x: 65, y: 45, voice: true, brain: false },
| { name: "Fomalhaut", constellation: "Piscis Austrinus", harnessed: false, x: 25, y: 55, voice: false, brain: false },
| { name: "Regulus", constellation: "Leo", harnessed: false, x: 40, y: 75, voice: false, brain: false }
| ];
|
| // List of all timezones (IANA) with display names and UTC offsets
| // For brevity, a representative subset of all timezones is included here.
| // In a real app, you would include all timezones.
| const timezones = [
| { id: "Pacific/Midway", name: "Midway Island", offset: "-11:00" },
| { id: "Pacific/Honolulu", name: "Hawaii", offset: "-10:00" },
| { id: "America/Anchorage", name: "Alaska", offset: "-09:00" },
| { id: "America/Los_Angeles", name: "Pacific Time (US & Canada)", offset: "-08:00" },
| { id: "America/Denver", name: "Mountain Time (US & Canada)", offset: "-07:00" },
| { id: "America/Chicago", name: "Central Time (US & Canada)", offset: "-06:00" },
| { id: "America/New_York", name: "Eastern Time (US & Canada)", offset: "-05:00" },
| { id: "America/Caracas", name: "Caracas", offset: "-04:30" },
| { id: "America/Halifax", name: "Atlantic Time (Canada)", offset: "-04:00" },
| { id: "America/St_Johns", name: "Newfoundland", offset: "-03:30" },
| { id: "America/Argentina/Buenos_Aires", name: "Buenos Aires", offset: "-03:00" },
| { id: "Atlantic/South_Georgia", name: "South Georgia", offset: "-02:00" },
| { id: "Atlantic/Azores", name: "Azores", offset: "-01:00" },
| { id: "Europe/London", name: "London", offset: "+00:00" },
| { id: "Europe/Berlin", name: "Berlin", offset: "+01:00" },
| { id: "Europe/Athens", name: "Athens", offset: "+02:00" },
| { id: "Europe/Moscow", name: "Moscow", offset: "+03:00" },
| { id: "Asia/Dubai", name: "Dubai", offset: "+04:00" },
| { id: "Asia/Karachi", name: "Karachi", offset: "+05:00" },
| { id: "Asia/Kolkata", name: "India Standard Time", offset: "+05:30" },
| { id: "Asia/Bangkok", name: "Bangkok", offset: "+07:00" },
| { id: "Asia/Shanghai", name: "Shanghai", offset: "+08:00" },
| { id: "Asia/Tokyo", name: "Tokyo", offset: "+09:00" },
| { id: "Australia/Sydney", name: "Sydney", offset: "+10:00" },
| { id: "Pacific/Auckland", name: "Auckland", offset: "+12:00" },
| { id: "Pacific/Chatham", name: "Chatham Islands", offset: "+12:45" }
| ];
|
| // Commands for terminal
| const commands = {
| help: {
| description: "List available commands",
| action: () => {
| return Object.entries(commands)
| .map(([cmd, obj]) => `${cmd} - ${obj.description}`)
| .join("\n");
| },
| },
| list: {
| description: "List stars and their harness status",
| action: () => {
| let output = "Harnessed Stars:\n";
| output += allStars.filter(s => s.harnessed).map(s => `- ${s.name} (${s.constellation})`).join("\n") + "\n\n";
| output += "Stars To Harness:\n";
| output += allStars.filter(s => !s.harnessed).map(s => `- ${s.name} (${s.constellation})`).join("\n");
| return output;
| },
| },
| harness: {
| description: "Start harnessing a star by name. Usage: harness [star name]",
| action: (args) => {
| if (!args.length) return "Error: No star name provided.";
| const starName = args.join(" ").toLowerCase();
| const star = allStars.find(s => s.name.toLowerCase() === starName);
| if (!star) return `Error: Star '${args.join(" ")}' not found.`;
| if (star.harnessed) return `Star '${star.name}' is already harnessed.`;
| star.harnessed = true;
| updateStarLists();
| addVial(star.name);
| updateStarDot(star.name);
| return `Star '${star.name}' is now harnessed and energy vial collected.`;
| },
| },
| unharness: {
| description: "Remove harness from a star by name. Usage: unharness [star name]",
| action: (args) => {
| if (!args.length) return "Error: No star name provided.";
| const starName = args.join(" ").toLowerCase();
| const star = allStars.find(s => s.name.toLowerCase() === starName);
| if (!star) return `Error: Star '${args.join(" ")}' not found.`;
| if (!star.harnessed) return `Star '${star.name}' is not harnessed.`;
| star.harnessed = false;
| updateStarLists();
| removeVial(star.name);
| updateStarDot(star.name);
| return `Star '${star.name}' harness removed and vial discarded.`;
| },
| },
| tasks: {
| description: "List tasks due for harnessing and energy management",
| action: () => {
| const toHarness = allStars.filter(s => !s.harnessed);
| if (!toHarness.length) return "All stars are harnessed. No pending tasks.";
| return toHarness.map(s => `- Harness star '${s.name}' in constellation '${s.constellation}'`).join("\n");
| },
| },
| status: {
| description: "Show current harnessing status",
| action: () => {
| const harnessedCount = allStars.filter(s => s.harnessed).length;
| const total = allStars.length;
| return `Harnessed ${harnessedCount} out of ${total} stars.\nVials collected: ${vials.length}`;
| },
| },
| clear: {
| description: "Clear terminal output",
| action: () => {
| terminalOutput.innerText = "";
| return "";
| },
| },
| voice: {
| description: "Toggle voice communication with a star. Usage: voice [star name]",
| action: (args) => {
| if (!args.length) return "Error: No star name provided.";
| const starName = args.join(" ").toLowerCase();
| const star = allStars.find(s => s.name.toLowerCase() === starName);
| if (!star) return `Error: Star '${args.join(" ")}' not found.`;
| star.voice = !star.voice;
| updateStarDot(star.name);
| return `Voice communication ${star.voice ? "enabled" : "disabled"} for star '${star.name}'.`;
| }
| },
| brain: {
| description: "Toggle brain insurance for a star. Usage: brain [star name]",
| action: (args) => {
| if (!args.length) return "Error: No star name provided.";
| if (currentUser !== "Antonio Rodriguez Jr.") return "Access denied: Only Antonio Rodriguez Jr. can toggle brain insurance.";
| const starName = args.join(" ").toLowerCase();
| const star = allStars.find(s => s.name.toLowerCase() === starName);
| if (!star) return `Error: Star '${args.join(" ")}' not found.`;
| star.brain = !star.brain;
| updateStarDot(star.name);
| return `Brain insurance ${star.brain ? "enabled" : "disabled"} for star '${star.name}'.`;
| }
| }
| };
|
| // Vials collected
| let vials = [];
|
| // Distributed vials mapped by timezone id
| let distributedVials = {};
|
| // DOM references
| const listHarnessed = document.getElementById("list-harnessed");
| const listToHarness = document.getElementById("list-to-harness");
| const vialsContainer = document.getElementById("vials-container");
| const distributionContainer = document.getElementById("distribution-container");
| const timezoneGrid = document.getElementById("timezone-grid");
| const btnStart = document.getElementById("btn-start");
| const btnStop = document.getElementById("btn-stop");
| const terminal = document.getElementById("terminal");
| const terminalOutput = document.getElementById("terminal-output");
| const terminalInput = document.getElementById("terminal-input");
| const beamsContainer = document.getElementById("beams-container");
| const sphere = document.getElementById("sphere");
| const tooltip = document.getElementById("tooltip");
| const voiceBrainInfo = document.getElementById("voice-brain-info");
|
| // Animation and harnessing state
| let harnessing = false;
| let harnessInterval = null;
| let currentHarnessIndex = 0;
|
| // Antonio Rodriguez Jr. special user check (simulate)
| const currentUser = "Antonio Rodriguez Jr.";
|
| // Initialize star lists
| function updateStarLists() {
| listHarnessed.innerHTML = "";
| listToHarness.innerHTML = "";
| allStars.forEach((star) => {
| const li = document.createElement("li");
| li.textContent = `${star.name} (${star.constellation})`;
| if (star.harnessed) {
| listHarnessed.appendChild(li);
| } else {
| listToHarness.appendChild(li);
| }
| });
| }
|
| // Add vial for star
| function addVial(starName) {
| if (!vials.includes(starName)) {
| vials.push(starName);
| renderVials();
| }
| }
|
| // Remove vial for star
| function removeVial(starName) {
| vials = vials.filter(v => v !== starName);
| // Also remove from distribution if present
| for (const tz in distributedVials) {
| distributedVials[tz] = distributedVials[tz].filter(v => v !== starName);
| if (distributedVials[tz].length === 0) delete distributedVials[tz];
| }
| renderVials();
| renderDistributedVials();
| updateTimezoneGrid();
| }
|
| // Render vials visually in vials container (draggable)
| function renderVials() {
| vialsContainer.innerHTML = "";
| vials.forEach((starName) => {
| const vial = document.createElement("div");
| vial.className = "star-filled-vial";
| vial.title = `Energy vial glowing green, representing collected energy from star ${starName}`;
| vial.setAttribute("draggable", "true");
| vial.setAttribute("aria-grabbed", "false");
| vial.setAttribute("tabindex", "0");
| vial.dataset.starName = starName;
| vial.innerHTML = `
| <img src="https://placehold.co/48x48/png?text=Vial" alt="Energy vial glowing green, representing collected energy from star ${starName}" class="w-full h-auto rounded-t" />
| <div class="vial-liquid"></div>
| <div class="text-xs text-green-300 text-center mt-1 select-none truncate" title="${starName}">${starName}</div>
| `;
| vialsContainer.appendChild(vial);
| });
| addDragAndDropListeners();
| }
|
| // Render distributed vials visually in distribution container
| function renderDistributedVials() {
| distributionContainer.innerHTML = "";
| for (const tz in distributedVials) {
| distributedVials[tz].forEach(starName => {
| const vial = document.createElement("div");
| vial.className = "star-filled-vial";
| vial.title = `Distributed energy vial from star ${starName} to timezone ${tz}`;
| vial.setAttribute("draggable", "true");
| vial.setAttribute("aria-grabbed", "false");
| vial.setAttribute("tabindex", "0");
| vial.dataset.starName = starName;
| vial.dataset.timezone = tz;
| vial.innerHTML = `
| <img src="https://placehold.co/48x48/png?text=Vial" alt="Distributed energy vial glowing green, representing collected energy from star ${starName} distributed to timezone ${tz}" class="w-full h-auto rounded-t" />
| <div class="vial-liquid"></div>
| <div class="text-xs text-green-300 text-center mt-1 select-none truncate" title="${starName}">${starName}</div>
| <div class="text-[8px] text-green-400 text-center select-none truncate mt-0.5" title="${tz}">${tz}</div>
| `;
| distributionContainer.appendChild(vial);
| });
| }
| addDragAndDropListeners();
| }
|
| // Create beams and star dots on sphere
| function createBeamsAndStars() {
| beamsContainer.innerHTML = "";
| allStars.forEach((star, index) => {
| // Create star dot
| const starDot = document.createElement("div");
| starDot.className = "star-dot";
| starDot.style.left = `${star.x}%`;
| starDot.style.top = `${star.y}%`;
| starDot.setAttribute("data-star-index", index);
| starDot.setAttribute("tabindex", "0");
| starDot.setAttribute("role", "button");
| starDot.setAttribute("aria-label", `Star ${star.name} in constellation ${star.constellation}, ${star.harnessed ? "harnessed" : "not harnessed"}`);
| starDot.title = `${star.name} (${star.constellation}) - ${star.harnessed ? "Harnessed" : "To Harness"}`;
| if (star.harnessed) {
| starDot.style.backgroundColor = "#4ade80";
| starDot.style.boxShadow = "0 0 12px #4ade80";
| } else {
| starDot.style.backgroundColor = "#eab308";
| starDot.style.boxShadow = "0 0 10px #ca8a04";
| }
| // Add voice icon overlay if voice enabled
| if (star.voice) {
| const voiceIcon = document.createElement("i");
| voiceIcon.className = "fas fa-microphone voice-icon";
| voiceIcon.style.position = "absolute";
| voiceIcon.style.top = "-6px";
| voiceIcon.style.right = "-6px";
| voiceIcon.style.fontSize = "0.75rem";
| voiceIcon.style.color = "#22c55e";
| starDot.appendChild(voiceIcon);
| }
| // Add brain icon overlay if brain insurance enabled
| if (star.brain) {
| const brainIcon = document.createElement("i");
| brainIcon.className = "fas fa-brain brain-icon";
| brainIcon.style.position = "absolute";
| brainIcon.style.bottom = "-6px";
| brainIcon.style.left = "-6px";
| brainIcon.style.fontSize = "0.75rem";
| brainIcon.style.color = "#22c55e";
| starDot.appendChild(brainIcon);
| }
| beamsContainer.appendChild(starDot);
|
| // Create beam line from sphere center to star dot
| const beamLine = document.createElement("div");
| beamLine.className = "beam-line";
| // Calculate distance and angle from center (50%,50%) to star (x,y)
| const centerX = 50;
| const centerY = 50;
| const dx = star.x - centerX;
| const dy = star.y - centerY;
| const distance = Math.sqrt(dx * dx + dy * dy);
| const angle = Math.atan2(dy, dx) * (180 / Math.PI) + 90; // +90 to align vertical top
| beamLine.style.height = `${distance * 1.4}%`; // scale length a bit longer
| beamLine.style.left = "50%";
| beamLine.style.top = "50%";
| beamLine.style.transform = `translateX(-50%) rotate(${angle}deg)`;
| beamsContainer.appendChild(beamLine);
| });
| }
|
| // Update star dot appearance after changes
| function updateStarDot(starName) {
| const starIndex = allStars.findIndex(s => s.name === starName);
| if (starIndex === -1) return;
| const star = allStars[starIndex];
| const starDot = beamsContainer.querySelector(`.star-dot[data-star-index="${starIndex}"]`);
| if (!starDot) return;
| // Update color and shadow
| if (star.harnessed) {
| starDot.style.backgroundColor = "#4ade80";
| starDot.style.boxShadow = "0 0 12px #4ade80";
| } else {
| starDot.style.backgroundColor = "#eab308";
| starDot.style.boxShadow = "0 0 10px #ca8a04";
| }
| // Remove existing voice and brain icons
| starDot.querySelectorAll(".voice-icon, .brain-icon").forEach(el => el.remove());
| // Add voice icon overlay if voice enabled
| if (star.voice) {
| const voiceIcon = document.createElement("i");
| voiceIcon.className = "fas fa-microphone voice-icon";
| voiceIcon.style.position = "absolute";
| voiceIcon.style.top = "-6px";
| voiceIcon.style.right = "-6px";
| voiceIcon.style.fontSize = "0.75rem";
| voiceIcon.style.color = "#22c55e";
| starDot.appendChild(voiceIcon);
| }
| // Add brain icon overlay if brain insurance enabled
| if (star.brain) {
| const brainIcon = document.createElement("i");
| brainIcon.className = "fas fa-brain brain-icon";
| brainIcon.style.position = "absolute";
| brainIcon.style.bottom = "-6px";
| brainIcon.style.left = "-6px";
| brainIcon.style.fontSize = "0.75rem";
| brainIcon.style.color = "#22c55e";
| starDot.appendChild(brainIcon);
| }
| starDot.title = `${star.name} (${star.constellation}) - ${star.harnessed ? "Harnessed" : "To Harness"}`;
| starDot.setAttribute("aria-label", `Star ${star.name} in constellation ${star.constellation}, ${star.harnessed ? "harnessed" : "not harnessed"}`);
| }
|
| // Animate harnessing sequence
| function startHarnessingSequence() {
| if (harnessing) return;
| harnessing = true;
| btnStart.disabled = true;
| btnStop.disabled = false;
| terminalInput.disabled = false;
| terminalInput.focus();
|
| terminalPrint("Starting harnessing sequence...");
| currentHarnessIndex = 0;
|
| harnessInterval = setInterval(() => {
| if (currentHarnessIndex >= allStars.length) {
| terminalPrint("Harnessing sequence complete.");
| stopHarnessingSequence();
| return;
| }
| const star = allStars[currentHarnessIndex];
| if (!star.harnessed) {
| star.harnessed = true;
| addVial(star.name);
| updateStarLists();
| updateStarDot(star.name);
| terminalPrint(`Harnessed star: ${star.name} (${star.constellation})`);
| animateBeamPulse(star);
| } else {
| terminalPrint(`Star already harnessed: ${star.name} (${star.constellation})`);
| }
| currentHarnessIndex++;
| }, 2500);
| }
|
| function stopHarnessingSequence() {
| if (!harnessing) return;
| harnessing = false;
| btnStart.disabled = false;
| btnStop.disabled = true;
| terminalInput.disabled = true;
| clearInterval(harnessInterval);
| terminalPrint("Harnessing sequence stopped. Consumption continues.");
| }
|
| // Terminal print helper
| function terminalPrint(text) {
| const p = document.createElement("div");
| p.textContent = text;
| terminalOutput.appendChild(p);
| terminal.scrollTop = terminal.scrollHeight;
| }
|
| // Terminal command handler
| function handleTerminalCommand(input) {
| if (!input.trim()) return;
| const parts = input.trim().split(/\s+/);
| const cmd = parts[0].toLowerCase();
| const args = parts.slice(1);
|
| if (!(cmd in commands)) {
| terminalPrint(`Error: Command '${cmd}' not recognized. Type 'help' for commands.`);
| return;
| }
|
| // Restrict some commands to Antonio Rodriguez Jr.
| const restrictedCommands = ["harness", "unharness", "brain"];
| if (restrictedCommands.includes(cmd) && currentUser !== "Antonio Rodriguez Jr.") {
| terminalPrint(`Access denied: Only Antonio Rodriguez Jr. can execute '${cmd}'.`);
| return;
| }
|
| const result = commands[cmd].action(args);
| if (result) terminalPrint(result);
| }
|
| // Terminal input event
| terminalInput.addEventListener("keydown", (e) => {
| if (e.key === "Enter") {
| e.preventDefault();
| const input = terminalInput.value;
| terminalPrint(`> ${input}`);
| handleTerminalCommand(input);
| terminalInput.value = "";
| }
| });
|
| // Start/Stop buttons events
| btnStart.addEventListener("click", () => {
| startHarnessingSequence();
| });
| btnStop.addEventListener("click", () => {
| stopHarnessingSequence();
| });
|
| // Animate beam pulse for a star
| function animateBeamPulse(star) {
| const starIndex = allStars.findIndex(s => s.name === star.name);
| if (starIndex === -1) return;
| // Find the beam line corresponding to star (beam lines are after star dots, so index*2+1)
| const beamLines = beamsContainer.querySelectorAll(".beam-line");
| const beamLine = beamLines[starIndex];
| if (!beamLine) return;
| beamLine.style.animation = "beam-glow-pulse 1.5s ease-in-out 3";
| beamLine.addEventListener("animationend", () => {
| beamLine.style.animation = "beam-glow 2s ease-in-out infinite alternate";
| }, { once: true });
| }
|
| // Add keyboard and mouse interaction for star dots
| function addStarDotInteractions() {
| beamsContainer.querySelectorAll(".star-dot").forEach(starDot => {
| starDot.addEventListener("mouseenter", (e) => {
| const index = parseInt(starDot.getAttribute("data-star-index"));
| showTooltip(e, allStars[index]);
| });
| starDot.addEventListener("mouseleave", () => {
| hideTooltip();
| });
| starDot.addEventListener("focus", (e) => {
| const index = parseInt(starDot.getAttribute("data-star-index"));
| showTooltip(e, allStars[index]);
| });
| starDot.addEventListener("blur", () => {
| hideTooltip();
| });
| starDot.addEventListener("click", () => {
| const index = parseInt(starDot.getAttribute("data-star-index"));
| const star = allStars[index];
| terminalPrint(`> harness ${star.name}`);
| if (star.harnessed) {
| terminalPrint(`Star '${star.name}' is already harnessed.`);
| } else {
| star.harnessed = true;
| addVial(star.name);
| updateStarLists();
| updateStarDot(star.name);
| terminalPrint(`Star '${star.name}' is now harnessed and energy vial collected.`);
| animateBeamPulse(star);
| }
| });
| starDot.addEventListener("keydown", (e) => {
| if (e.key === "Enter" || e.key === " ") {
| e.preventDefault();
| starDot.click();
| }
| });
| });
| }
|
| // Tooltip show/hide
| function showTooltip(event, star) {
| tooltip.textContent = `${star.name} (${star.constellation}) - ${star.harnessed ? "Harnessed" : "To Harness"}`;
| tooltip.style.left = `${event.target.offsetLeft + 20}px`;
| tooltip.style.top = `${event.target.offsetTop - 30}px`;
| tooltip.classList.add("visible");
| tooltip.setAttribute("aria-hidden", "false");
| }
| function hideTooltip() {
| tooltip.classList.remove("visible");
| tooltip.setAttribute("aria-hidden", "true");
| }
|
| // Drag & Drop handlers for vials and distribution
|
| function addDragAndDropListeners() {
| // Draggables
| const draggables = document.querySelectorAll(".star-filled-vial[draggable='true']");
| draggables.forEach(draggable => {
| draggable.removeEventListener("dragstart", onDragStart);
| draggable.removeEventListener("dragend", onDragEnd);
| draggable.addEventListener("dragstart", onDragStart);
| draggable.addEventListener("dragend", onDragEnd);
| draggable.removeEventListener("keydown", onDraggableKeyDown);
| draggable.addEventListener("keydown", onDraggableKeyDown);
| });
|
| // Drop zones
| [vialsContainer, distributionContainer].forEach(zone => {
| zone.removeEventListener("dragover", onDragOver);
| zone.removeEventListener("drop", onDrop);
| zone.removeEventListener("dragleave", onDragLeave);
| zone.addEventListener("dragover", onDragOver);
| zone.addEventListener("drop", onDrop);
| zone.addEventListener("dragleave", onDragLeave);
| });
| }
|
| let draggedVial = null;
|
| function onDragStart(e) {
| draggedVial = e.target;
| e.dataTransfer.effectAllowed = "move";
| e.dataTransfer.setData("text/plain", draggedVial.dataset.starName);
| draggedVial.setAttribute("aria-grabbed", "true");
| setTimeout(() => {
| draggedVial.style.visibility = "hidden";
| }, 0);
| }
|
| function onDragEnd(e) {
| if (draggedVial) {
| draggedVial.style.visibility = "visible";
| draggedVial.setAttribute("aria-grabbed", "false");
| draggedVial = null;
| }
| [vialsContainer, distributionContainer].forEach(zone => {
| zone.classList.remove("dragover");
| });
| }
|
| function onDragOver(e) {
| e.preventDefault();
| e.dataTransfer.dropEffect = "move";
| e.currentTarget.classList.add("dragover");
| }
|
| function onDragLeave(e) {
| e.currentTarget.classList.remove("dragover");
| }
|
| function onDrop(e) {
| e.preventDefault();
| e.currentTarget.classList.remove("dragover");
| const starName = e.dataTransfer.getData("text/plain");
| if (!starName) return;
|
| // Determine source and target containers
| const sourceIsVials = vials.includes(starName);
| const targetIsVials = e.currentTarget === vialsContainer;
| const targetIsDistribution = e.currentTarget === distributionContainer;
|
| if (sourceIsVials && targetIsDistribution) {
| // Move vial from vials to distribution - assign to a timezone
| // Prompt user to select timezone
| promptTimezoneSelection(starName);
| } else if (!sourceIsVials && targetIsVials) {
| // Move vial back from distribution to vials (remove from distribution)
| removeVialFromDistribution(starName);
| }
| }
|
| // Prompt user to select timezone for vial distribution
| function promptTimezoneSelection(starName) {
| // Create modal-like prompt with timezone grid and confirm button
| const modal = document.createElement("div");
| modal.setAttribute("role", "dialog");
| modal.setAttribute("aria-modal", "true");
| modal.setAttribute("aria-label", `Select timezone to distribute energy vial from star ${starName}`);
| modal.style.position = "fixed";
| modal.style.top = "0";
| modal.style.left = "0";
| modal.style.width = "100vw";
| modal.style.height = "100vh";
| modal.style.backgroundColor = "rgba(0,0,0,0.85)";
| modal.style.display = "flex";
| modal.style.flexDirection = "column";
| modal.style.justifyContent = "center";
| modal.style.alignItems = "center";
| modal.style.zIndex = "9999";
| modal.style.padding = "1rem";
|
| const container = document.createElement("div");
| container.style.backgroundColor = "#111827";
| container.style.border = "2px solid #22c55e";
| container.style.borderRadius = "0.75rem";
| container.style.padding = "1rem";
| container.style.maxWidth = "600px";
| container.style.width = "100%";
| container.style.maxHeight = "80vh";
| container.style.overflowY = "auto";
| container.style.display = "flex";
| container.style.flexDirection = "column";
| container.style.gap = "1rem";
|
| const title = document.createElement("h2");
| title.textContent = `Select Timezone for Vial: ${starName}`;
| title.style.color = "#22c55e";
| title.style.fontFamily = "'Orbitron', monospace";
| title.style.marginBottom = "0.5rem";
| container.appendChild(title);
|
| const tzGrid = document.createElement("div");
| tzGrid.style.display = "grid";
| tzGrid.style.gridTemplateColumns = "repeat(auto-fill,minmax(120px,1fr))";
| tzGrid.style.gap = "0.5rem";
| tzGrid.style.maxHeight = "50vh";
| tzGrid.style.overflowY = "auto";
|
| let selectedTz = null;
|
| timezones.forEach(tz => {
| const block = document.createElement("button");
| block.type = "button";
| block.className = "timezone-block";
| block.textContent = `${tz.name} (${tz.offset})`;
| block.style.userSelect = "none";
| block.style.border = "1px solid #22c55e";
| block.style.backgroundColor = "#064e3b";
| block.style.color = "#a7f3d0";
| block.style.borderRadius = "0.5rem";
| block.style.padding = "0.5rem";
| block.style.fontSize = "0.75rem";
| block.style.cursor = "pointer";
| block.setAttribute("aria-pressed", "false");
| block.addEventListener("click", () => {
| // Deselect all
| Array.from(tzGrid.children).forEach(c => {
| c.classList.remove("active");
| c.setAttribute("aria-pressed", "false");
| });
| block.classList.add("active");
| block.setAttribute("aria-pressed", "true");
| selectedTz = tz.id;
| confirmBtn.disabled = false;
| confirmBtn.focus();
| });
| tzGrid.appendChild(block);
| });
|
| container.appendChild(tzGrid);
|
| const btnContainer = document.createElement("div");
| btnContainer.style.display = "flex";
| btnContainer.style.justifyContent = "flex-end";
| btnContainer.style.gap = "1rem";
|
| const cancelBtn = document.createElement("button");
| cancelBtn.type = "button";
| cancelBtn.textContent = "Cancel";
| cancelBtn.className = "btn-red px-3 py-1 rounded";
| cancelBtn.addEventListener("click", () => {
| document.body.removeChild(modal);
| });
|
| const confirmBtn = document.createElement("button");
| confirmBtn.type = "button";
| confirmBtn.textContent = "Confirm";
| confirmBtn.className = "btn-green px-3 py-1 rounded";
| confirmBtn.disabled = true;
| confirmBtn.addEventListener("click", () => {
| if (!selectedTz) return;
| distributeVialToTimezone(starName, selectedTz);
| document.body.removeChild(modal);
| });
|
| btnContainer.appendChild(cancelBtn);
| btnContainer.appendChild(confirmBtn);
| container.appendChild(btnContainer);
|
| modal.appendChild(container);
| document.body.appendChild(modal);
|
| // Focus first timezone block for accessibility
| const firstTzBtn = tzGrid.querySelector("button");
| if (firstTzBtn) firstTzBtn.focus();
| }
|
| // Distribute vial to timezone
| function distributeVialToTimezone(starName, timezoneId) {
| // Remove vial from vials container
| vials = vials.filter(v => v !== starName);
| // Add vial to distribution mapping
| if (!distributedVials[timezoneId]) {
| distributedVials[timezoneId] = [];
| }
| if (!distributedVials[timezoneId].includes(starName)) {
| distributedVials[timezoneId].push(starName);
| }
| renderVials();
| renderDistributedVials();
| updateTimezoneGrid();
| terminalPrint(`Distributed vial from star '${starName}' to timezone '${timezoneId}'.`);
| }
|
| // Remove vial from distribution (back to vials container)
| function removeVialFromDistribution(starName) {
| let found = false;
| for (const tz in distributedVials) {
| const index = distributedVials[tz].indexOf(starName);
| if (index !== -1) {
| distributedVials[tz].splice(index, 1);
| if (distributedVials[tz].length === 0) delete distributedVials[tz];
| found = true;
| break;
| }
| }
| if (found) {
| vials.push(starName);
| renderVials();
| renderDistributedVials();
| updateTimezoneGrid();
| terminalPrint(`Removed vial from distribution for star '${starName}'.`);
| }
| }
|
| // Update timezone grid to show which timezones have energy distributed
| function updateTimezoneGrid() {
| timezoneGrid.innerHTML = "";
| timezones.forEach(tz => {
| const block = document.createElement("div");
| block.className = "timezone-block";
| block.textContent = `${tz.name} (${tz.offset})`;
| if (distributedVials[tz.id] && distributedVials[tz.id].length > 0) {
| block.classList.add("active");
| block.title = `Energy vials distributed: ${distributedVials[tz.id].join(", ")}`;
| } else {
| block.title = "No energy distributed";
| }
| timezoneGrid.appendChild(block);
| });
| }
|
| // Drag & Drop keyboard support for vials
| function onDraggableKeyDown(e) {
| if (e.key === "Enter" || e.key === " ") {
| e.preventDefault();
| const vial = e.currentTarget;
| if (vial.parentElement === vialsContainer) {
| // Move vial to distribution - prompt timezone selection
| promptTimezoneSelection(vial.dataset.starName);
| } else if (vial.parentElement === distributionContainer) {
| // Move vial back to vials container
| removeVialFromDistribution(vial.dataset.starName);
| }
| }
| }
|
| // Initial render
| updateStarLists();
| renderVials();
| renderDistributedVials();
| createBeamsAndStars();
| addStarDotInteractions();
| updateTimezoneGrid();
|
| // Initial terminal welcome message
| terminalPrint("Welcome to the Star Communication Terminal.");
| terminalPrint("Type 'help' to see available commands.");
|
| // Accessibility: focus terminal input on load
| window.addEventListener("load", () => {
| terminalInput.disabled = true;
| });
| </script>
| </body>
| </html>
<html class="scroll-smooth" lang="en">
| <head>
| <meta charset="utf-8"/>
| <meta content="width=device-width, initial-scale=1" name="viewport"/>
| <title>
| Smart Sphere Star Harnessing App
| </title>
| <script src="
https://cdn.tailwindcss.com">
| </script>
| <link href="
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet"/>
| <link href="
https://fonts.googleapis.com/css2?family=Orbitron&family=Roboto+Mono&display=swap" rel="stylesheet"/>
| <style>
| body {
| font-family: 'Roboto Mono', monospace;
| background-color: #0f172a;
| color: #d1d5db;
| }
| .terminal {
| background-color: #111827;
| border-radius: 0.5rem;
| box-shadow: 0 0 15px #22c55e;
| font-family: 'Roboto Mono', monospace;
| font-size: 0.875rem;
| line-height: 1.25rem;
| color: #22c55e;
| padding: 1rem;
| min-height: 300px;
| overflow-y: auto;
| white-space: pre-wrap;
| user-select: text;
| }
| .terminal-input {
| outline: none;
| border: none;
| background: transparent;
| color: #22c55e;
| font-family: 'Roboto Mono', monospace;
| font-size: 0.875rem;
| width: 100%;
| caret-color: #22c55e;
| }
| .scrollbar-thin::-webkit-scrollbar {
| width: 6px;
| }
| .scrollbar-thin::-webkit-scrollbar-track {
| background: transparent;
| }
| .scrollbar-thin::-webkit-scrollbar-thumb {
| background-color: #22c55e;
| border-radius: 3px;
| }
| .star-filled-vial {
| width: 48px;
| height: 96px;
| background: linear-gradient(180deg, #22c55e 0%, #166534 100%);
| border-radius: 0.75rem 0.75rem 0.25rem 0.25rem;
| box-shadow: 0 0 8px #22c55e;
| position: relative;
| margin: 0.25rem;
| display: flex;
| flex-direction: column;
| justify-content: flex-end;
| overflow: hidden;
| cursor: grab;
| transition: transform 0.3s ease;
| }
| .star-filled-vial:active {
| cursor: grabbing;
| transform: scale(1.1);
| box-shadow: 0 0 20px #4ade80;
| z-index: 1000;
| }
| .star-filled-vial:hover {
| transform: scale(1.1);
| box-shadow: 0 0 15px #4ade80;
| z-index: 10;
| }
| .star-filled-vial::before {
| content: '';
| position: absolute;
| top: 0.25rem;
| left: 50%;
| transform: translateX(-50%);
| width: 24px;
| height: 12px;
| background: #166534;
| border-radius: 12px 12px 0 0;
| box-shadow: inset 0 2px 4px #22c55e;
| z-index: 10;
| }
| .vial-liquid {
| background: #22c55e;
| height: 60%;
| border-radius: 0 0 0.75rem 0.75rem;
| box-shadow: inset 0 0 10px #4ade80;
| transition: height 0.5s ease;
| }
| .btn-green {
| background-color: #22c55e;
| color: #0f172a;
| font-weight: 600;
| transition: background-color 0.3s ease;
| }
| .btn-green:hover:not(:disabled) {
| background-color: #16a34a;
| }
| .btn-green:disabled {
| background-color: #4ade80;
| cursor: not-allowed;
| }
| .btn-red {
| background-color: #dc2626;
| color: #fef2f2;
| font-weight: 600;
| transition: background-color 0.3s ease;
| }
| .btn-red:hover:not(:disabled) {
| background-color: #b91c1c;
| }
| .btn-red:disabled {
| background-color: #fca5a5;
| cursor: not-allowed;
| }
| .btn-yellow {
| background-color: #eab308;
| color: #1e293b;
| font-weight: 600;
| transition: background-color 0.3s ease;
| }
| .btn-yellow:hover {
| background-color: #ca8a04;
| }
| .scrollbar-thin {
| scrollbar-width: thin;
| scrollbar-color: #22c55e transparent;
| }
| /* Sphere container and beams animation */
| .sphere-container {
| position: relative;
| width: 100%;
| max-width: 400px;
| aspect-ratio: 1 / 1;
| margin: 0 auto;
| perspective: 1200px;
| }
| .sphere {
| width: 100%;
| height: 100%;
| border-radius: 50%;
| background: radial-gradient(circle at center, #22c55e 20%, #064e3b 90%);
| box-shadow:
| inset 0 0 20px #4ade80,
| 0 0 30px #22c55e;
| position: relative;
| transform-style: preserve-3d;
| animation: sphere-rotate 20s linear infinite;
| }
| @keyframes sphere-rotate {
| 0% {
| transform: rotateX(0deg) rotateY(0deg);
| }
| 100% {
| transform: rotateX(360deg) rotateY(360deg);
| }
| }
| /* Beams container */
| .beams-container {
| position: absolute;
| top: 50%;
| left: 50%;
| width: 100%;
| height: 100%;
| pointer-events: none;
| transform-style: preserve-3d;
| transform-origin: center center;
| animation: beams-pulse 3s ease-in-out infinite;
| }
| @keyframes beams-pulse {
| 0%, 100% {
| filter: drop-shadow(0 0 6px #22c55e);
| }
| 50% {
| filter: drop-shadow(0 0 12px #4ade80);
| }
| }
| /* Beam line */
| .beam-line {
| position: absolute;
| width: 2px;
| background: linear-gradient(180deg, #22c55e, transparent);
| border-radius: 1px;
| transform-origin: top center;
| animation: beam-glow 2s ease-in-out infinite alternate;
| filter: drop-shadow(0 0 4px #22c55e);
| }
| @keyframes beam-glow {
| 0% {
| opacity: 0.6;
| box-shadow: 0 0 6px #22c55e;
| }
| 100% {
| opacity: 1;
| box-shadow: 0 0 14px #4ade80;
| }
| }
| /* Star dot */
| .star-dot {
| position: absolute;
| width: 12px;
| height: 12px;
| background: #22c55e;
| border-radius: 50%;
| box-shadow: 0 0 8px #4ade80;
| cursor: pointer;
| transition: transform 0.3s ease;
| }
| .star-dot:hover {
| transform: scale(1.5);
| box-shadow: 0 0 20px #86efac;
| z-index: 20;
| }
| /* Voice & Brain info box */
| .info-box {
| background: #064e3b;
| border: 2px solid #22c55e;
| border-radius: 0.5rem;
| padding: 1rem;
| margin-top: 1rem;
| color: #a7f3d0;
| font-size: 0.9rem;
| font-family: 'Roboto Mono', monospace;
| user-select: none;
| }
| /* Voice icon animation */
| .voice-icon {
| animation: pulse-voice 2s infinite;
| color: #22c55e;
| font-size: 1.5rem;
| vertical-align: middle;
| margin-right: 0.5rem;
| }
| @keyframes pulse-voice {
| 0%, 100% {
| opacity: 1;
| text-shadow: 0 0 6px #22c55e;
| }
| 50% {
| opacity: 0.6;
| text-shadow: 0 0 12px #4ade80;
| }
| }
| /* Brain icon animation */
| .brain-icon {
| animation: pulse-brain 3s infinite;
| color: #22c55e;
| font-size: 1.5rem;
| vertical-align: middle;
| margin-right: 0.5rem;
| }
| @keyframes pulse-brain {
| 0%, 100% {
| opacity: 1;
| text-shadow: 0 0 6px #22c55e;
| }
| 50% {
| opacity: 0.7;
| text-shadow: 0 0 14px #4ade80;
| }
| }
| /* Scrollable star list with custom scrollbar */
| .star-list {
| max-height: 180px;
| overflow-y: auto;
| scrollbar-width: thin;
| scrollbar-color: #22c55e transparent;
| }
| .star-list::-webkit-scrollbar {
| width: 6px;
| }
| .star-list::-webkit-scrollbar-track {
| background: transparent;
| }
| .star-list::-webkit-scrollbar-thumb {
| background-color: #22c55e;
| border-radius: 3px;
| }
| /* Tooltip for star dots */
| .tooltip {
| position: absolute;
| background: #064e3b;
| border: 1px solid #22c55e;
| padding: 0.25rem 0.5rem;
| border-radius: 0.25rem;
| font-size: 0.75rem;
| color: #a7f3d0;
| pointer-events: none;
| white-space: nowrap;
| user-select: none;
| z-index: 50;
| opacity: 0;
| transition: opacity 0.2s ease;
| }
| .tooltip.visible {
| opacity: 1;
| }
| /* Drag & Drop container styles */
| #vials-container, #distribution-container {
| min-height: 120px;
| border: 2px dashed #22c55e;
| border-radius: 0.5rem;
| padding: 0.5rem;
| display: flex;
| flex-wrap: wrap;
| gap: 0.5rem;
| background-color: #0f172a;
| transition: background-color 0.3s ease;
| }
| #vials-container.dragover, #distribution-container.dragover {
| background-color: #164e2e;
| border-color: #4ade80;
| }
| /* Distribution section */
| #distribution-section {
| background-color: #111827;
| border-radius: 0.75rem;
| padding: 1rem;
| margin-top: 1rem;
| color: #a7f3d0;
| font-family: 'Roboto Mono', monospace;
| }
| #distribution-section h3 {
| font-family: 'Orbitron', monospace;
| color: #22c55e;
| margin-bottom: 0.5rem;
| }
| /* Timezone grid */
| #timezone-grid {
| display: grid;
| grid-template-columns: repeat(auto-fill,minmax(120px,1fr));
| gap: 0.5rem;
| max-height: 300px;
| overflow-y: auto;
| border: 1px solid #22c55e;
| border-radius: 0.5rem;
| padding: 0.5rem;
| background-color: #0f172a;
| }
| .timezone-block {
| background-color: #064e3b;
| border: 1px solid #22c55e;
| border-radius: 0.5rem;
| padding: 0.5rem;
| font-size: 0.75rem;
| text-align: center;
| user-select: none;
| cursor: default;
| color: #a7f3d0;
| display: flex;
| flex-direction: column;
| justify-content: center;
| align-items: center;
| min-height: 60px;
| transition: background-color 0.3s ease;
| }
| .timezone-block.active {
| background-color: #22c55e;
| color: #0f172a;
| font-weight: 700;
| box-shadow: 0 0 10px #4ade80;
| }
| /* Responsive tweaks */
| @media (max-width: 768px) {
| main {
| grid-template-columns: 1fr !important;
| }
| #distribution-section {
| margin-top: 1.5rem;
| }
| }
| </style>
| </head>
| <body class="min-h-screen flex flex-col">
| <header class="bg-gray-900 p-4 flex flex-col md:flex-row items-center justify-between">
| <div class="flex items-center space-x-3">
| <img alt="Smart tracking sphere, metallic silver with green glowing lines, floating in space" class="w-12 h-12 rounded-full" src="
https://placehold.co/48x48/png?text=Sphere"/>
| <h1 class="text-2xl font-orbitron font-bold text-green-400 select-none">
| Smart Sphere Star Harnessing
| </h1>
| </div>
| <nav class="mt-3 md:mt-0">
| <ul class="flex space-x-6 text-green-300 font-semibold text-sm select-none">
| <li>
| <button aria-label="Start harnessing process" class="btn-green px-3 py-1 rounded flex items-center space-x-2" id="btn-start">
| <i aria-hidden="true" class="fas fa-play">
| </i>
| <span>
| Start Harness
| </span>
| </button>
| </li>
| <li>
| <button aria-label="Stop harnessing process" class="btn-red px-3 py-1 rounded flex items-center space-x-2" disabled="" id="btn-stop">
| <i aria-hidden="true" class="fas fa-stop">
| </i>
| <span>
| Stop Harness
| </span>
| </button>
| </li>
| </ul>
| </nav>
| </header>
| <main class="flex-grow p-4 max-w-7xl mx-auto grid grid-cols-1 md:grid-cols-4 gap-6">
| <!-- Sphere & Beams Section -->
| <section class="col-span-1 md:col-span-2 bg-gray-800 rounded-lg p-4 flex flex-col items-center relative">
| <div aria-label="Smart sphere with tracking beams" class="sphere-container">
| <div class="sphere" id="sphere">
| </div>
| <div aria-hidden="true" class="beams-container" id="beams-container">
| </div>
| <div aria-hidden="true" class="tooltip" id="tooltip" role="tooltip">
| </div>
| </div>
| <p class="mt-4 text-green-300 text-center font-mono text-sm max-w-xl">
| The sphere intelligently tracks stars and harnesses their energy by searching constellations and individual stars. Click on stars to see details.
| </p>
| <div aria-atomic="true" aria-live="polite" class="info-box mt-6 w-full max-w-xl" id="voice-brain-info">
| <div class="flex items-center mb-2">
| <i aria-hidden="true" class="fas fa-microphone voice-icon">
| </i>
| <span>
| <strong>
| Voice Enabled:
| </strong>
| The sphere can communicate with stars using voice commands.
| </span>
| </div>
| <div class="flex items-center">
| <i aria-hidden="true" class="fas fa-brain brain-icon">
| </i>
| <span>
| <strong>
| Brain Insurance:
| </strong>
| Only
| <em>
| Antonio Rodriguez Jr.
| </em>
| can convert, channel, stream, listen, touch, smell, feel, and manage star energy.
| </span>
| </div>
| </div>
| </section>
| <!-- Star List & Vials Section -->
| <section class="col-span-1 md:col-span-2 bg-gray-900 rounded-lg p-4 flex flex-col">
| <h2 class="text-green-400 font-orbitron text-xl mb-3 select-none">
| Stars Harnessed & To Harness
| </h2>
| <div class="flex flex-col space-y-4 overflow-y-auto max-h-[400px] scrollbar-thin pr-2">
| <div>
| <h3 class="text-green-300 font-semibold mb-1">
| Harnessed Stars
| </h3>
| <ul aria-label="List of harnessed stars" class="list-disc list-inside text-green-200 star-list" id="list-harnessed" tabindex="0">
| </ul>
| </div>
| <div>
| <h3 class="text-yellow-400 font-semibold mb-1">
| Stars To Harness
| </h3>
| <ul aria-label="List of stars to harness" class="list-disc list-inside text-yellow-300 star-list" id="list-to-harness" tabindex="0">
| </ul>
| </div>
| </div>
| <h2 class="text-green-400 font-orbitron text-xl mt-6 mb-3 select-none">
| Collected Vials (Drag to Distribute Energy)
| </h2>
| <div aria-dropeffect="move" aria-label="Collected energy vials" class="flex flex-wrap gap-2 min-h-[120px]" id="vials-container" tabindex="0">
| </div>
| <section aria-label="Energy distribution section" id="distribution-section" tabindex="0">
| <h3>
| Energy Distribution Across Timezones
| </h3>
| <p class="mb-2 text-sm text-green-300">
| Drag vials here to distribute star energy to real-life locations worldwide using IP blocks and timezone coverage. All timezones are included to ensure universal interest reception.
| </p>
| <div aria-dropeffect="move" aria-label="Distributed energy vials container" class="min-h-[120px] flex flex-wrap gap-2" id="distribution-container" tabindex="0">
| </div>
| <h3 class="mt-4">
| Timezones
| </h3>
| <div aria-label="List of all world timezones with energy distribution status" id="timezone-grid" tabindex="0">
| </div>
| </section>
| </section>
| </main>
| <!-- Terminal Section -->
| <section class="bg-gray-900 p-4 max-w-7xl mx-auto rounded-lg mt-6 mb-6">
| <h2 class="text-green-400 font-orbitron text-xl mb-3 select-none">
| Star Communication Terminal
| </h2>
| <div aria-atomic="true" aria-label="Star communication terminal" aria-live="polite" aria-multiline="true" class="terminal scrollbar-thin" contenteditable="false" id="terminal" role="textbox" tabindex="0">
| <div aria-atomic="true" aria-live="polite" class="mb-2" id="terminal-output">
| </div>
| <div class="flex items-center space-x-2">
| <span aria-hidden="true" class="text-green-400 font-bold select-none">
| >
| </span>
| <input aria-label="Terminal command input" autocomplete="off" class="terminal-input flex-grow" disabled="" id="terminal-input" spellcheck="false" type="text"/>
| </div>
| </div>
| </section>
| <script>
| // Data for stars with 3D positions (x,y in % relative to sphere container)
| const allStars = [
| { name: "Sirius", constellation: "Canis Major", harnessed: true, x: 70, y: 30, voice: true, brain: true },
| { name: "Betelgeuse", constellation: "Orion", harnessed: true, x: 40, y: 20, voice: true, brain: false },
| { name: "Rigel", constellation: "Orion", harnessed: false, x: 45, y: 60, voice: false, brain: false },
| { name: "Vega", constellation: "Lyra", harnessed: false, x: 80, y: 50, voice: false, brain: false },
| { name: "Polaris", constellation: "Ursa Minor", harnessed: true, x: 50, y: 10, voice: true, brain: true },
| { name: "Altair", constellation: "Aquila", harnessed: false, x: 60, y: 70, voice: false, brain: false },
| { name: "Aldebaran", constellation: "Taurus", harnessed: false, x: 30, y: 40, voice: false, brain: false },
| { name: "Antares", constellation: "Scorpius", harnessed: false, x: 20, y: 65, voice: false, brain: false },
| { name: "Spica", constellation: "Virgo", harnessed: true, x: 35, y: 25, voice: true, brain: false },
| { name: "Deneb", constellation: "Cygnus", harnessed: false, x: 75, y: 75, voice: false, brain: false },
| { name: "Castor", constellation: "Gemini", harnessed: false, x: 55, y: 35, voice: false, brain: false },
| { name: "Pollux", constellation: "Gemini", harnessed: false, x: 58, y: 38, voice: false, brain: false },
| { name: "Procyon", constellation: "Canis Minor", harnessed: true, x: 65, y: 45, voice: true, brain: false },
| { name: "Fomalhaut", constellation: "Piscis Austrinus", harnessed: false, x: 25, y: 55, voice: false, brain: false },
| { name: "Regulus", constellation: "Leo", harnessed: false, x: 40, y: 75, voice: false, brain: false }
| ];
|
| // List of all timezones (IANA) with display names and UTC offsets
| // For brevity, a representative subset of all timezones is included here.
| // In a real app, you would include all timezones.
| const timezones = [
| { id: "Pacific/Midway", name: "Midway Island", offset: "-11:00" },
| { id: "Pacific/Honolulu", name: "Hawaii", offset: "-10:00" },
| { id: "America/Anchorage", name: "Alaska", offset: "-09:00" },
| { id: "America/Los_Angeles", name: "Pacific Time (US & Canada)", offset: "-08:00" },
| { id: "America/Denver", name: "Mountain Time (US & Canada)", offset: "-07:00" },
| { id: "America/Chicago", name: "Central Time (US & Canada)", offset: "-06:00" },
| { id: "America/New_York", name: "Eastern Time (US & Canada)", offset: "-05:00" },
| { id: "America/Caracas", name: "Caracas", offset: "-04:30" },
| { id: "America/Halifax", name: "Atlantic Time (Canada)", offset: "-04:00" },
| { id: "America/St_Johns", name: "Newfoundland", offset: "-03:30" },
| { id: "America/Argentina/Buenos_Aires", name: "Buenos Aires", offset: "-03:00" },
| { id: "Atlantic/South_Georgia", name: "South Georgia", offset: "-02:00" },
| { id: "Atlantic/Azores", name: "Azores", offset: "-01:00" },
| { id: "Europe/London", name: "London", offset: "+00:00" },
| { id: "Europe/Berlin", name: "Berlin", offset: "+01:00" },
| { id: "Europe/Athens", name: "Athens", offset: "+02:00" },
| { id: "Europe/Moscow", name: "Moscow", offset: "+03:00" },
| { id: "Asia/Dubai", name: "Dubai", offset: "+04:00" },
| { id: "Asia/Karachi", name: "Karachi", offset: "+05:00" },
| { id: "Asia/Kolkata", name: "India Standard Time", offset: "+05:30" },
| { id: "Asia/Bangkok", name: "Bangkok", offset: "+07:00" },
| { id: "Asia/Shanghai", name: "Shanghai", offset: "+08:00" },
| { id: "Asia/Tokyo", name: "Tokyo", offset: "+09:00" },
| { id: "Australia/Sydney", name: "Sydney", offset: "+10:00" },
| { id: "Pacific/Auckland", name: "Auckland", offset: "+12:00" },
| { id: "Pacific/Chatham", name: "Chatham Islands", offset: "+12:45" }
| ];
|
| // Commands for terminal
| const commands = {
| help: {
| description: "List available commands",
| action: () => {
| return Object.entries(commands)
| .map(([cmd, obj]) => `${cmd} - ${obj.description}`)
| .join("\n");
| },
| },
| list: {
| description: "List stars and their harness status",
| action: () => {
| let output = "Harnessed Stars:\n";
| output += allStars.filter(s => s.harnessed).map(s => `- ${s.name} (${s.constellation})`).join("\n") + "\n\n";
| output += "Stars To Harness:\n";
| output += allStars.filter(s => !s.harnessed).map(s => `- ${s.name} (${s.constellation})`).join("\n");
| return output;
| },
| },
| harness: {
| description: "Start harnessing a star by name. Usage: harness [star name]",
| action: (args) => {
| if (!args.length) return "Error: No star name provided.";
| const starName = args.join(" ").toLowerCase();
| const star = allStars.find(s => s.name.toLowerCase() === starName);
| if (!star) return `Error: Star '${args.join(" ")}' not found.`;
| if (star.harnessed) return `Star '${star.name}' is already harnessed.`;
| star.harnessed = true;
| updateStarLists();
| addVial(star.name);
| updateStarDot(star.name);
| return `Star '${star.name}' is now harnessed and energy vial collected.`;
| },
| },
| unharness: {
| description: "Remove harness from a star by name. Usage: unharness [star name]",
| action: (args) => {
| if (!args.length) return "Error: No star name provided.";
| const starName = args.join(" ").toLowerCase();
| const star = allStars.find(s => s.name.toLowerCase() === starName);
| if (!star) return `Error: Star '${args.join(" ")}' not found.`;
| if (!star.harnessed) return `Star '${star.name}' is not harnessed.`;
| star.harnessed = false;
| updateStarLists();
| removeVial(star.name);
| updateStarDot(star.name);
| return `Star '${star.name}' harness removed and vial discarded.`;
| },
| },
| tasks: {
| description: "List tasks due for harnessing and energy management",
| action: () => {
| const toHarness = allStars.filter(s => !s.harnessed);
| if (!toHarness.length) return "All stars are harnessed. No pending tasks.";
| return toHarness.map(s => `- Harness star '${s.name}' in constellation '${s.constellation}'`).join("\n");
| },
| },
| status: {
| description: "Show current harnessing status",
| action: () => {
| const harnessedCount = allStars.filter(s => s.harnessed).length;
| const total = allStars.length;
| return `Harnessed ${harnessedCount} out of ${total} stars.\nVials collected: ${vials.length}`;
| },
| },
| clear: {
| description: "Clear terminal output",
| action: () => {
| terminalOutput.innerText = "";
| return "";
| },
| },
| voice: {
| description: "Toggle voice communication with a star. Usage: voice [star name]",
| action: (args) => {
| if (!args.length) return "Error: No star name provided.";
| const starName = args.join(" ").toLowerCase();
| const star = allStars.find(s => s.name.toLowerCase() === starName);
| if (!star) return `Error: Star '${args.join(" ")}' not found.`;
| star.voice = !star.voice;
| updateStarDot(star.name);
| return `Voice communication ${star.voice ? "enabled" : "disabled"} for star '${star.name}'.`;
| }
| },
| brain: {
| description: "Toggle brain insurance for a star. Usage: brain [star name]",
| action: (args) => {
| if (!args.length) return "Error: No star name provided.";
| if (currentUser !== "Antonio Rodriguez Jr.") return "Access denied: Only Antonio Rodriguez Jr. can toggle brain insurance.";
| const starName = args.join(" ").toLowerCase();
| const star = allStars.find(s => s.name.toLowerCase() === starName);
| if (!star) return `Error: Star '${args.join(" ")}' not found.`;
| star.brain = !star.brain;
| updateStarDot(star.name);
| return `Brain insurance ${star.brain ? "enabled" : "disabled"} for star '${star.name}'.`;
| }
| }
| };
|
| // Vials collected
| let vials = [];
|
| // Distributed vials mapped by timezone id
| let distributedVials = {};
|
| // DOM references
| const listHarnessed = document.getElementById("list-harnessed");
| const listToHarness = document.getElementById("list-to-harness");
| const vialsContainer = document.getElementById("vials-container");
| const distributionContainer = document.getElementById("distribution-container");
| const timezoneGrid = document.getElementById("timezone-grid");
| const btnStart = document.getElementById("btn-start");
| const btnStop = document.getElementById("btn-stop");
| const terminal = document.getElementById("terminal");
| const terminalOutput = document.getElementById("terminal-output");
| const terminalInput = document.getElementById("terminal-input");
| const beamsContainer = document.getElementById("beams-container");
| const sphere = document.getElementById("sphere");
| const tooltip = document.getElementById("tooltip");
| const voiceBrainInfo = document.getElementById("voice-brain-info");
|
| // Animation and harnessing state
| let harnessing = false;
| let harnessInterval = null;
| let currentHarnessIndex = 0;
|
| // Antonio Rodriguez Jr. special user check (simulate)
| const currentUser = "Antonio Rodriguez Jr.";
|
| // Initialize star lists
| function updateStarLists() {
| listHarnessed.innerHTML = "";
| listToHarness.innerHTML = "";
| allStars.forEach((star) => {
| const li = document.createElement("li");
| li.textContent = `${star.name} (${star.constellation})`;
| if (star.harnessed) {
| listHarnessed.appendChild(li);
| } else {
| listToHarness.appendChild(li);
| }
| });
| }
|
| // Add vial for star
| function addVial(starName) {
| if (!vials.includes(starName)) {
| vials.push(starName);
| renderVials();
| }
| }
|
| // Remove vial for star
| function removeVial(starName) {
| vials = vials.filter(v => v !== starName);
| // Also remove from distribution if present
| for (const tz in distributedVials) {
| distributedVials[tz] = distributedVials[tz].filter(v => v !== starName);
| if (distributedVials[tz].length === 0) delete distributedVials[tz];
| }
| renderVials();
| renderDistributedVials();
| updateTimezoneGrid();
| }
|
| // Render vials visually in vials container (draggable)
| function renderVials() {
| vialsContainer.innerHTML = "";
| vials.forEach((starName) => {
| const vial = document.createElement("div");
| vial.className = "star-filled-vial";
| vial.title = `Energy vial glowing green, representing collected energy from star ${starName}`;
| vial.setAttribute("draggable", "true");
| vial.setAttribute("aria-grabbed", "false");
| vial.setAttribute("tabindex", "0");
| vial.dataset.starName = starName;
| vial.innerHTML = `
| <img src="https://placehold.co/48x48/png?text=Vial" alt="Energy vial glowing green, representing collected energy from star ${starName}" class="w-full h-auto rounded-t" />
| <div class="vial-liquid"></div>
| <div class="text-xs text-green-300 text-center mt-1 select-none truncate" title="${starName}">${starName}</div>
| `;
| vialsContainer.appendChild(vial);
| });
| addDragAndDropListeners();
| }
|
| // Render distributed vials visually in distribution container
| function renderDistributedVials() {
| distributionContainer.innerHTML = "";
| for (const tz in distributedVials) {
| distributedVials[tz].forEach(starName => {
| const vial = document.createElement("div");
| vial.className = "star-filled-vial";
| vial.title = `Distributed energy vial from star ${starName} to timezone ${tz}`;
| vial.setAttribute("draggable", "true");
| vial.setAttribute("aria-grabbed", "false");
| vial.setAttribute("tabindex", "0");
| vial.dataset.starName = starName;
| vial.dataset.timezone = tz;
| vial.innerHTML = `
| <img src="https://placehold.co/48x48/png?text=Vial" alt="Distributed energy vial glowing green, representing collected energy from star ${starName} distributed to timezone ${tz}" class="w-full h-auto rounded-t" />
| <div class="vial-liquid"></div>
| <div class="text-xs text-green-300 text-center mt-1 select-none truncate" title="${starName}">${starName}</div>
| <div class="text-[8px] text-green-400 text-center select-none truncate mt-0.5" title="${tz}">${tz}</div>
| `;
| distributionContainer.appendChild(vial);
| });
| }
| addDragAndDropListeners();
| }
|
| // Create beams and star dots on sphere
| function createBeamsAndStars() {
| beamsContainer.innerHTML = "";
| allStars.forEach((star, index) => {
| // Create star dot
| const starDot = document.createElement("div");
| starDot.className = "star-dot";
| starDot.style.left = `${star.x}%`;
| starDot.style.top = `${star.y}%`;
| starDot.setAttribute("data-star-index", index);
| starDot.setAttribute("tabindex", "0");
| starDot.setAttribute("role", "button");
| starDot.setAttribute("aria-label", `Star ${star.name} in constellation ${star.constellation}, ${star.harnessed ? "harnessed" : "not harnessed"}`);
| starDot.title = `${star.name} (${star.constellation}) - ${star.harnessed ? "Harnessed" : "To Harness"}`;
| if (star.harnessed) {
| starDot.style.backgroundColor = "#4ade80";
| starDot.style.boxShadow = "0 0 12px #4ade80";
| } else {
| starDot.style.backgroundColor = "#eab308";
| starDot.style.boxShadow = "0 0 10px #ca8a04";
| }
| // Add voice icon overlay if voice enabled
| if (star.voice) {
| const voiceIcon = document.createElement("i");
| voiceIcon.className = "fas fa-microphone voice-icon";
| voiceIcon.style.position = "absolute";
| voiceIcon.style.top = "-6px";
| voiceIcon.style.right = "-6px";
| voiceIcon.style.fontSize = "0.75rem";
| voiceIcon.style.color = "#22c55e";
| starDot.appendChild(voiceIcon);
| }
| // Add brain icon overlay if brain insurance enabled
| if (star.brain) {
| const brainIcon = document.createElement("i");
| brainIcon.className = "fas fa-brain brain-icon";
| brainIcon.style.position = "absolute";
| brainIcon.style.bottom = "-6px";
| brainIcon.style.left = "-6px";
| brainIcon.style.fontSize = "0.75rem";
| brainIcon.style.color = "#22c55e";
| starDot.appendChild(brainIcon);
| }
| beamsContainer.appendChild(starDot);
|
| // Create beam line from sphere center to star dot
| const beamLine = document.createElement("div");
| beamLine.className = "beam-line";
| // Calculate distance and angle from center (50%,50%) to star (x,y)
| const centerX = 50;
| const centerY = 50;
| const dx = star.x - centerX;
| const dy = star.y - centerY;
| const distance = Math.sqrt(dx * dx + dy * dy);
| const angle = Math.atan2(dy, dx) * (180 / Math.PI) + 90; // +90 to align vertical top
| beamLine.style.height = `${distance * 1.4}%`; // scale length a bit longer
| beamLine.style.left = "50%";
| beamLine.style.top = "50%";
| beamLine.style.transform = `translateX(-50%) rotate(${angle}deg)`;
| beamsContainer.appendChild(beamLine);
| });
| }
|
| // Update star dot appearance after changes
| function updateStarDot(starName) {
| const starIndex = allStars.findIndex(s => s.name === starName);
| if (starIndex === -1) return;
| const star = allStars[starIndex];
| const starDot = beamsContainer.querySelector(`.star-dot[data-star-index="${starIndex}"]`);
| if (!starDot) return;
| // Update color and shadow
| if (star.harnessed) {
| starDot.style.backgroundColor = "#4ade80";
| starDot.style.boxShadow = "0 0 12px #4ade80";
| } else {
| starDot.style.backgroundColor = "#eab308";
| starDot.style.boxShadow = "0 0 10px #ca8a04";
| }
| // Remove existing voice and brain icons
| starDot.querySelectorAll(".voice-icon, .brain-icon").forEach(el => el.remove());
| // Add voice icon overlay if voice enabled
| if (star.voice) {
| const voiceIcon = document.createElement("i");
| voiceIcon.className = "fas fa-microphone voice-icon";
| voiceIcon.style.position = "absolute";
| voiceIcon.style.top = "-6px";
| voiceIcon.style.right = "-6px";
| voiceIcon.style.fontSize = "0.75rem";
| voiceIcon.style.color = "#22c55e";
| starDot.appendChild(voiceIcon);
| }
| // Add brain icon overlay if brain insurance enabled
| if (star.brain) {
| const brainIcon = document.createElement("i");
| brainIcon.className = "fas fa-brain brain-icon";
| brainIcon.style.position = "absolute";
| brainIcon.style.bottom = "-6px";
| brainIcon.style.left = "-6px";
| brainIcon.style.fontSize = "0.75rem";
| brainIcon.style.color = "#22c55e";
| starDot.appendChild(brainIcon);
| }
| starDot.title = `${star.name} (${star.constellation}) - ${star.harnessed ? "Harnessed" : "To Harness"}`;
| starDot.setAttribute("aria-label", `Star ${star.name} in constellation ${star.constellation}, ${star.harnessed ? "harnessed" : "not harnessed"}`);
| }
|
| // Animate harnessing sequence
| function startHarnessingSequence() {
| if (harnessing) return;
| harnessing = true;
| btnStart.disabled = true;
| btnStop.disabled = false;
| terminalInput.disabled = false;
| terminalInput.focus();
|
| terminalPrint("Starting harnessing sequence...");
| currentHarnessIndex = 0;
|
| harnessInterval = setInterval(() => {
| if (currentHarnessIndex >= allStars.length) {
| terminalPrint("Harnessing sequence complete.");
| stopHarnessingSequence();
| return;
| }
| const star = allStars[currentHarnessIndex];
| if (!star.harnessed) {
| star.harnessed = true;
| addVial(star.name);
| updateStarLists();
| updateStarDot(star.name);
| terminalPrint(`Harnessed star: ${star.name} (${star.constellation})`);
| animateBeamPulse(star);
| } else {
| terminalPrint(`Star already harnessed: ${star.name} (${star.constellation})`);
| }
| currentHarnessIndex++;
| }, 2500);
| }
|
| function stopHarnessingSequence() {
| if (!harnessing) return;
| harnessing = false;
| btnStart.disabled = false;
| btnStop.disabled = true;
| terminalInput.disabled = true;
| clearInterval(harnessInterval);
| terminalPrint("Harnessing sequence stopped. Consumption continues.");
| }
|
| // Terminal print helper
| function terminalPrint(text) {
| const p = document.createElement("div");
| p.textContent = text;
| terminalOutput.appendChild(p);
| terminal.scrollTop = terminal.scrollHeight;
| }
|
| // Terminal command handler
| function handleTerminalCommand(input) {
| if (!input.trim()) return;
| const parts = input.trim().split(/\s+/);
| const cmd = parts[0].toLowerCase();
| const args = parts.slice(1);
|
| if (!(cmd in commands)) {
| terminalPrint(`Error: Command '${cmd}' not recognized. Type 'help' for commands.`);
| return;
| }
|
| // Restrict some commands to Antonio Rodriguez Jr.
| const restrictedCommands = ["harness", "unharness", "brain"];
| if (restrictedCommands.includes(cmd) && currentUser !== "Antonio Rodriguez Jr.") {
| terminalPrint(`Access denied: Only Antonio Rodriguez Jr. can execute '${cmd}'.`);
| return;
| }
|
| const result = commands[cmd].action(args);
| if (result) terminalPrint(result);
| }
|
| // Terminal input event
| terminalInput.addEventListener("keydown", (e) => {
| if (e.key === "Enter") {
| e.preventDefault();
| const input = terminalInput.value;
| terminalPrint(`> ${input}`);
| handleTerminalCommand(input);
| terminalInput.value = "";
| }
| });
|
| // Start/Stop buttons events
| btnStart.addEventListener("click", () => {
| startHarnessingSequence();
| });
| btnStop.addEventListener("click", () => {
| stopHarnessingSequence();
| });
|
| // Animate beam pulse for a star
| function animateBeamPulse(star) {
| const starIndex = allStars.findIndex(s => s.name === star.name);
| if (starIndex === -1) return;
| // Find the beam line corresponding to star (beam lines are after star dots, so index*2+1)
| const beamLines = beamsContainer.querySelectorAll(".beam-line");
| const beamLine = beamLines[starIndex];
| if (!beamLine) return;
| beamLine.style.animation = "beam-glow-pulse 1.5s ease-in-out 3";
| beamLine.addEventListener("animationend", () => {
| beamLine.style.animation = "beam-glow 2s ease-in-out infinite alternate";
| }, { once: true });
| }
|
| // Add keyboard and mouse interaction for star dots
| function addStarDotInteractions() {
| beamsContainer.querySelectorAll(".star-dot").forEach(starDot => {
| starDot.addEventListener("mouseenter", (e) => {
| const index = parseInt(starDot.getAttribute("data-star-index"));
| showTooltip(e, allStars[index]);
| });
| starDot.addEventListener("mouseleave", () => {
| hideTooltip();
| });
| starDot.addEventListener("focus", (e) => {
| const index = parseInt(starDot.getAttribute("data-star-index"));
| showTooltip(e, allStars[index]);
| });
| starDot.addEventListener("blur", () => {
| hideTooltip();
| });
| starDot.addEventListener("click", () => {
| const index = parseInt(starDot.getAttribute("data-star-index"));
| const star = allStars[index];
| terminalPrint(`> harness ${star.name}`);
| if (star.harnessed) {
| terminalPrint(`Star '${star.name}' is already harnessed.`);
| } else {
| star.harnessed = true;
| addVial(star.name);
| updateStarLists();
| updateStarDot(star.name);
| terminalPrint(`Star '${star.name}' is now harnessed and energy vial collected.`);
| animateBeamPulse(star);
| }
| });
| starDot.addEventListener("keydown", (e) => {
| if (e.key === "Enter" || e.key === " ") {
| e.preventDefault();
| starDot.click();
| }
| });
| });
| }
|
| // Tooltip show/hide
| function showTooltip(event, star) {
| tooltip.textContent = `${star.name} (${star.constellation}) - ${star.harnessed ? "Harnessed" : "To Harness"}`;
| tooltip.style.left = `${event.target.offsetLeft + 20}px`;
| tooltip.style.top = `${event.target.offsetTop - 30}px`;
| tooltip.classList.add("visible");
| tooltip.setAttribute("aria-hidden", "false");
| }
| function hideTooltip() {
| tooltip.classList.remove("visible");
| tooltip.setAttribute("aria-hidden", "true");
| }
|
| // Drag & Drop handlers for vials and distribution
|
| function addDragAndDropListeners() {
| // Draggables
| const draggables = document.querySelectorAll(".star-filled-vial[draggable='true']");
| draggables.forEach(draggable => {
| draggable.removeEventListener("dragstart", onDragStart);
| draggable.removeEventListener("dragend", onDragEnd);
| draggable.addEventListener("dragstart", onDragStart);
| draggable.addEventListener("dragend", onDragEnd);
| draggable.removeEventListener("keydown", onDraggableKeyDown);
| draggable.addEventListener("keydown", onDraggableKeyDown);
| });
|
| // Drop zones
| [vialsContainer, distributionContainer].forEach(zone => {
| zone.removeEventListener("dragover", onDragOver);
| zone.removeEventListener("drop", onDrop);
| zone.removeEventListener("dragleave", onDragLeave);
| zone.addEventListener("dragover", onDragOver);
| zone.addEventListener("drop", onDrop);
| zone.addEventListener("dragleave", onDragLeave);
| });
| }
|
| let draggedVial = null;
|
| function onDragStart(e) {
| draggedVial = e.target;
| e.dataTransfer.effectAllowed = "move";
| e.dataTransfer.setData("text/plain", draggedVial.dataset.starName);
| draggedVial.setAttribute("aria-grabbed", "true");
| setTimeout(() => {
| draggedVial.style.visibility = "hidden";
| }, 0);
| }
|
| function onDragEnd(e) {
| if (draggedVial) {
| draggedVial.style.visibility = "visible";
| draggedVial.setAttribute("aria-grabbed", "false");
| draggedVial = null;
| }
| [vialsContainer, distributionContainer].forEach(zone => {
| zone.classList.remove("dragover");
| });
| }
|
| function onDragOver(e) {
| e.preventDefault();
| e.dataTransfer.dropEffect = "move";
| e.currentTarget.classList.add("dragover");
| }
|
| function onDragLeave(e) {
| e.currentTarget.classList.remove("dragover");
| }
|
| function onDrop(e) {
| e.preventDefault();
| e.currentTarget.classList.remove("dragover");
| const starName = e.dataTransfer.getData("text/plain");
| if (!starName) return;
|
| // Determine source and target containers
| const sourceIsVials = vials.includes(starName);
| const targetIsVials = e.currentTarget === vialsContainer;
| const targetIsDistribution = e.currentTarget === distributionContainer;
|
| if (sourceIsVials && targetIsDistribution) {
| // Move vial from vials to distribution - assign to a timezone
| // Prompt user to select timezone
| promptTimezoneSelection(starName);
| } else if (!sourceIsVials && targetIsVials) {
| // Move vial back from distribution to vials (remove from distribution)
| removeVialFromDistribution(starName);
| }
| }
|
| // Prompt user to select timezone for vial distribution
| function promptTimezoneSelection(starName) {
| // Create modal-like prompt with timezone grid and confirm button
| const modal = document.createElement("div");
| modal.setAttribute("role", "dialog");
| modal.setAttribute("aria-modal", "true");
| modal.setAttribute("aria-label", `Select timezone to distribute energy vial from star ${starName}`);
| modal.style.position = "fixed";
| modal.style.top = "0";
| modal.style.left = "0";
| modal.style.width = "100vw";
| modal.style.height = "100vh";
| modal.style.backgroundColor = "rgba(0,0,0,0.85)";
| modal.style.display = "flex";
| modal.style.flexDirection = "column";
| modal.style.justifyContent = "center";
| modal.style.alignItems = "center";
| modal.style.zIndex = "9999";
| modal.style.padding = "1rem";
|
| const container = document.createElement("div");
| container.style.backgroundColor = "#111827";
| container.style.border = "2px solid #22c55e";
| container.style.borderRadius = "0.75rem";
| container.style.padding = "1rem";
| container.style.maxWidth = "600px";
| container.style.width = "100%";
| container.style.maxHeight = "80vh";
| container.style.overflowY = "auto";
| container.style.display = "flex";
| container.style.flexDirection = "column";
| container.style.gap = "1rem";
|
| const title = document.createElement("h2");
| title.textContent = `Select Timezone for Vial: ${starName}`;
| title.style.color = "#22c55e";
| title.style.fontFamily = "'Orbitron', monospace";
| title.style.marginBottom = "0.5rem";
| container.appendChild(title);
|
| const tzGrid = document.createElement("div");
| tzGrid.style.display = "grid";
| tzGrid.style.gridTemplateColumns = "repeat(auto-fill,minmax(120px,1fr))";
| tzGrid.style.gap = "0.5rem";
| tzGrid.style.maxHeight = "50vh";
| tzGrid.style.overflowY = "auto";
|
| let selectedTz = null;
|
| timezones.forEach(tz => {
| const block = document.createElement("button");
| block.type = "button";
| block.className = "timezone-block";
| block.textContent = `${tz.name} (${tz.offset})`;
| block.style.userSelect = "none";
| block.style.border = "1px solid #22c55e";
| block.style.backgroundColor = "#064e3b";
| block.style.color = "#a7f3d0";
| block.style.borderRadius = "0.5rem";
| block.style.padding = "0.5rem";
| block.style.fontSize = "0.75rem";
| block.style.cursor = "pointer";
| block.setAttribute("aria-pressed", "false");
| block.addEventListener("click", () => {
| // Deselect all
| Array.from(tzGrid.children).forEach(c => {
| c.classList.remove("active");
| c.setAttribute("aria-pressed", "false");
| });
| block.classList.add("active");
| block.setAttribute("aria-pressed", "true");
| selectedTz = tz.id;
| confirmBtn.disabled = false;
| confirmBtn.focus();
| });
| tzGrid.appendChild(block);
| });
|
| container.appendChild(tzGrid);
|
| const btnContainer = document.createElement("div");
| btnContainer.style.display = "flex";
| btnContainer.style.justifyContent = "flex-end";
| btnContainer.style.gap = "1rem";
|
| const cancelBtn = document.createElement("button");
| cancelBtn.type = "button";
| cancelBtn.textContent = "Cancel";
| cancelBtn.className = "btn-red px-3 py-1 rounded";
| cancelBtn.addEventListener("click", () => {
| document.body.removeChild(modal);
| });
|
| const confirmBtn = document.createElement("button");
| confirmBtn.type = "button";
| confirmBtn.textContent = "Confirm";
| confirmBtn.className = "btn-green px-3 py-1 rounded";
| confirmBtn.disabled = true;
| confirmBtn.addEventListener("click", () => {
| if (!selectedTz) return;
| distributeVialToTimezone(starName, selectedTz);
| document.body.removeChild(modal);
| });
|
| btnContainer.appendChild(cancelBtn);
| btnContainer.appendChild(confirmBtn);
| container.appendChild(btnContainer);
|
| modal.appendChild(container);
| document.body.appendChild(modal);
|
| // Focus first timezone block for accessibility
| const firstTzBtn = tzGrid.querySelector("button");
| if (firstTzBtn) firstTzBtn.focus();
| }
|
| // Distribute vial to timezone
| function distributeVialToTimezone(starName, timezoneId) {
| // Remove vial from vials container
| vials = vials.filter(v => v !== starName);
| // Add vial to distribution mapping
| if (!distributedVials[timezoneId]) {
| distributedVials[timezoneId] = [];
| }
| if (!distributedVials[timezoneId].includes(starName)) {
| distributedVials[timezoneId].push(starName);
| }
| renderVials();
| renderDistributedVials();
| updateTimezoneGrid();
| terminalPrint(`Distributed vial from star '${starName}' to timezone '${timezoneId}'.`);
| }
|
| // Remove vial from distribution (back to vials container)
| function removeVialFromDistribution(starName) {
| let found = false;
| for (const tz in distributedVials) {
| const index = distributedVials[tz].indexOf(starName);
| if (index !== -1) {
| distributedVials[tz].splice(index, 1);
| if (distributedVials[tz].length === 0) delete distributedVials[tz];
| found = true;
| break;
| }
| }
| if (found) {
| vials.push(starName);
| renderVials();
| renderDistributedVials();
| updateTimezoneGrid();
| terminalPrint(`Removed vial from distribution for star '${starName}'.`);
| }
| }
|
| // Update timezone grid to show which timezones have energy distributed
| function updateTimezoneGrid() {
| timezoneGrid.innerHTML = "";
| timezones.forEach(tz => {
| const block = document.createElement("div");
| block.className = "timezone-block";
| block.textContent = `${tz.name} (${tz.offset})`;
| if (distributedVials[tz.id] && distributedVials[tz.id].length > 0) {
| block.classList.add("active");
| block.title = `Energy vials distributed: ${distributedVials[tz.id].join(", ")}`;
| } else {
| block.title = "No energy distributed";
| }
| timezoneGrid.appendChild(block);
| });
| }
|
| // Drag & Drop keyboard support for vials
| function onDraggableKeyDown(e) {
| if (e.key === "Enter" || e.key === " ") {
| e.preventDefault();
| const vial = e.currentTarget;
| if (vial.parentElement === vialsContainer) {
| // Move vial to distribution - prompt timezone selection
| promptTimezoneSelection(vial.dataset.starName);
| } else if (vial.parentElement === distributionContainer) {
| // Move vial back to vials container
| removeVialFromDistribution(vial.dataset.starName);
| }
| }
| }
|
| // Initial render
| updateStarLists();
| renderVials();
| renderDistributedVials();
| createBeamsAndStars();
| addStarDotInteractions();
| updateTimezoneGrid();
|
| // Initial terminal welcome message
| terminalPrint("Welcome to the Star Communication Terminal.");
| terminalPrint("Type 'help' to see available commands.");
|
| // Accessibility: focus terminal input on load
| window.addEventListener("load", () => {
| terminalInput.disabled = true;
| });
| </script>
| </body>
| </html>