/** @param {NS} ns */ export async function main(ns) { ns.disableLog('sleep'); // Disable log spamming let counter = 0; let incrementValue = 1; let isRunning = true; let isMinimized = false; // Tracks whether the window is minimized or not // Define colors from the provided theme const theme = { primary: "#0c0", primarylight: "#0f0", primarydark: "#090", error: "#c00", backgroundprimary: "#000", // Black background button: "#333", // Button background buttonHoverLight: "#555", // Lighter button hover effect buttonHoverDark: "#111", // Darker button hover effect rippleColor: "rgba(255, 255, 255, 0.5)", // Color of the ripple effect border: "#666" // Border color }; // Create a div for the display (the main window) const doc = eval("document"); let container = doc.createElement("div"); container.style = ` position: fixed; top: 100px; left: 100px; background: ${theme.backgroundprimary}; /* Solid black background */ color: ${theme.primary}; /* Primary color for text */ padding: 5px; z-index: 1000; font-family: monospace; border: 2px solid ${theme.border}; /* Border around the whole window */ width: 220px; border-radius: 5px; `; doc.body.appendChild(container); // Create title bar with ^ and X buttons (minimize and close) let titleBar = doc.createElement("div"); titleBar.style = ` display: flex; justify-content: space-between; align-items: center; font-weight: bold; color: ${theme.primarylight}; /* Light primary color for header */ cursor: default; padding-bottom: 5px; border-bottom: 1px solid ${theme.border}; /* Border between title and content */ `; container.appendChild(titleBar); let title = doc.createElement("span"); title.innerText = "Overview Counter"; titleBar.appendChild(title); let controls = doc.createElement("div"); // Create minimize button (^ for minimize/restore) let minimizeButton = doc.createElement("button"); minimizeButton.innerText = "^"; minimizeButton.style = ` background: none; border: none; color: ${theme.primarylight}; /* Light primary color for minimize button */ cursor: pointer; font-weight: bold; padding: 0 5px; `; controls.appendChild(minimizeButton); // Create close button (X to close) let closeButton = doc.createElement("button"); closeButton.innerText = "X"; closeButton.style = ` background: none; border: none; color: ${theme.error}; /* Error color for close button */ cursor: pointer; font-weight: bold; padding: 0 5px; `; controls.appendChild(closeButton); titleBar.appendChild(controls); // Create the content area (display for counter and buttons) let content = doc.createElement("div"); content.style = "margin-top: 10px;"; container.appendChild(content); let counterDisplay = doc.createElement("p"); counterDisplay.style = ` margin: 5px 0; color: ${theme.primarylight}; /* Primary light color for counter text */ `; content.appendChild(counterDisplay); // Function to apply button styles with hover and ripple effects function createStyledButton(text) { let button = doc.createElement("button"); button.innerText = text; button.style = ` position: relative; overflow: hidden; /* Allow ripple effect to be confined inside the button */ background: ${theme.button}; /* Button background color */ color: ${theme.primary}; /* Primary color for button text */ border: 1px solid ${theme.border}; cursor: pointer; margin-right: 5px; margin-bottom: 5px; padding: 5px; width: 100%; border-radius: 3px; transition: background-color 0.3s ease; /* Smooth transition for hover effect */ `; // Apply hover effect (lighter if button is dark, darker if light) button.addEventListener("mouseenter", () => { button.style.backgroundColor = theme.button === "#333" ? theme.buttonHoverLight : theme.buttonHoverDark; }); button.addEventListener("mouseleave", () => { button.style.backgroundColor = theme.button; }); // Add ripple effect on click button.addEventListener("click", (e) => { let ripple = doc.createElement("span"); let size = Math.max(button.offsetWidth, button.offsetHeight); let x = e.clientX - button.getBoundingClientRect().left - size / 2; let y = e.clientY - button.getBoundingClientRect().top - size / 2; ripple.style = ` position: absolute; width: ${size}px; height: ${size}px; background: ${theme.rippleColor}; border-radius: 50%; opacity: 0; animation: ripple-animation 0.6s ease-out; left: ${x}px; top: ${y}px; `; button.appendChild(ripple); // Remove ripple element after animation ripple.addEventListener("animationend", () => { ripple.remove(); }); }); return button; } // Add keyframes for ripple animation const styleSheet = doc.styleSheets[0]; styleSheet.insertRule(` @keyframes ripple-animation { from { transform: scale(0); opacity: 0.6; } to { transform: scale(4); opacity: 0; } } `, styleSheet.cssRules.length); // Create buttons with hover effects, animations, and ripple effect let incrementButton = createStyledButton("Increase Increment"); let decrementButton = createStyledButton("Decrease Increment"); let pauseButton = createStyledButton("Pause/Resume"); let quitButton = createStyledButton("Quit"); content.appendChild(incrementButton); content.appendChild(decrementButton); content.appendChild(pauseButton); content.appendChild(quitButton); // Add event listeners for the buttons incrementButton.addEventListener("click", () => incrementValue += 1); decrementButton.addEventListener("click", () => incrementValue = Math.max(0, incrementValue - 1)); pauseButton.addEventListener("click", () => incrementValue = incrementValue === 0 ? 1 : 0); quitButton.addEventListener("click", () => { isRunning = false; container.remove(); // Remove the container on quit }); // Minimize/Restore window minimizeButton.addEventListener("click", () => { isMinimized = !isMinimized; content.style.display = isMinimized ? "none" : "block"; }); // Close window closeButton.addEventListener("click", () => { isRunning = false; container.remove(); // Remove the window }); // Make the window draggable let isDragging = false; let offsetX, offsetY; container.addEventListener("mousedown", (e) => { isDragging = true; offsetX = e.clientX - container.getBoundingClientRect().left; offsetY = e.clientY - container.getBoundingClientRect().top; }); doc.addEventListener("mousemove", (e) => { if (isDragging) { container.style.left = `${e.clientX - offsetX}px`; container.style.top = `${e.clientY - offsetY}px`; } }); doc.addEventListener("mouseup", () => { isDragging = false; }); // Main loop to update the counter display while (isRunning) { counter += incrementValue; counterDisplay.innerText = `Counter: ${counter}\nIncrement Value: ${incrementValue}`; await ns.sleep(1000); // Sleep 1 second between updates } // Remove the container when the script stops container.remove(); ns.tprint("Script terminated."); }