Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (function() {
- // 1. CSS
- const style = document.createElement('style');
- style.innerHTML = `
- #twow-gradient-hud input::-webkit-outer-spin-button,
- #twow-gradient-hud input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
- #twow-gradient-hud input[type=number], #twow-gradient-hud select { -moz-appearance: textfield; text-align: center; }
- .hud-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; gap: 4px; }
- .hud-label { font-size: 9px; width: 30px; text-align: right; font-weight: bold; transition: color 0.3s; }
- .hud-input { background: #222; color: #fff; border: 1px solid #444; border-radius: 3px; padding: 3px; font-size: 11px; flex-grow: 1; width: 35px; }
- .hud-slider { flex-grow: 1; height: 4px; cursor: pointer; accent-color: #00FFCC; }
- .hidden { display: none !important; }
- #menu-btn { cursor: pointer; font-size: 12px; transition: transform 0.3s; }
- #menu-btn:hover { transform: rotate(45deg); color: #fff; }
- .btn-half { width: 49%; height: 30px; color:#fff; border:none; border-radius:4px; font-weight:bold; cursor:pointer; font-size:10px; margin-top:6px; transition: opacity 0.2s; }
- `;
- document.head.appendChild(style);
- // Helpers
- const hexToRGB = (str) => {
- const hex = str.startsWith('#') ? str.slice(1) : str;
- const arr = [];
- for (let i = 0; i < 3; i++) arr.push(parseInt(hex.slice(i * 2, i * 2 + 2), 16) || 0);
- return arr;
- };
- const hsvToRgb = (h, s, v) => {
- let r, g, b, i = Math.floor(h * 6), f = h * 6 - i, p = v * (1 - s), q = v * (1 - f * s), t = v * (1 - (1 - f) * s);
- switch (i % 6) {
- case 0: r = v, g = t, b = p; break;
- case 1: r = q, g = v, b = p; break;
- case 2: r = p, g = v, b = t; break;
- case 3: r = p, g = q, b = v; break;
- case 4: r = t, g = p, b = v; break;
- case 5: r = v, g = p, b = q; break;
- }
- return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
- };
- const lerp = (a, b, t) => a + (b - a) * t;
- const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
- async function executeGradient(cols, steps, startX, startY, delay, angleDeg, width, pattern, text, wrapLimit, isRainbow) {
- if (typeof writeCharAt !== 'function') return alert("writeCharAt missing!");
- const rgbCols = cols.map(hexToRGB);
- const angleRad = (angleDeg * Math.PI) / 180;
- const perpRad = angleRad + Math.PI / 2;
- const drawLimit = text.length > 0 ? text.length : steps;
- let lineOffset = 0, charInLine = 0;
- for (let i = 0; i < drawLimit; i++) {
- if (wrapLimit > 0 && charInLine >= wrapLimit) { lineOffset++; charInLine = 0; }
- const progress = i / (drawLimit - 1 || 1);
- let c;
- if (isRainbow) {
- c = hsvToRgb(progress, 1, 1);
- } else {
- const segmentProgress = progress * (rgbCols.length - 1);
- const index = Math.min(rgbCols.length - 2, Math.floor(segmentProgress));
- const t = segmentProgress % 1;
- c = [Math.round(lerp(rgbCols[index][0], rgbCols[index + 1][0], t)), Math.round(lerp(rgbCols[index][1], rgbCols[index + 1][1], t)), Math.round(lerp(rgbCols[index][2], rgbCols[index + 1][2], t))];
- }
- const char = text.length > 0 ? text[i] : "█";
- let baseX = startX + charInLine * Math.cos(angleRad), baseY = startY + charInLine * Math.sin(angleRad);
- if (lineOffset > 0) { baseX += lineOffset * 1.5 * Math.cos(perpRad); baseY += lineOffset * 1.5 * Math.sin(perpRad); }
- let patternOffset = 0;
- if (pattern === "wave") patternOffset = Math.sin(progress * Math.PI * 4) * 8;
- else if (pattern === "zag") patternOffset = (Math.abs(((progress * 4) % 1) - 0.5) * 4 - 1) * 8;
- if (pattern === "radial" && text.length === 0) {
- const pts = i * 6;
- for (let p = 0; p < pts; p++) {
- const sA = (p / pts) * Math.PI * 2;
- writeCharAt(char, c, Math.round(startX + i * Math.cos(sA)), -Math.round(startY + i * Math.sin(sA)));
- }
- } else if (pattern === "spiral" && text.length === 0) {
- const rot = progress * Math.PI * 10;
- writeCharAt(char, c, Math.round(startX + i * Math.cos(rot)), -Math.round(startY + i * Math.sin(rot)));
- } else {
- const dW = text.length > 0 ? 1 : width;
- for (let w = 0; w < dW; w++) {
- const off = (w - Math.floor(dW / 2)) + patternOffset;
- writeCharAt(char, c, Math.round(baseX + off * Math.cos(perpRad)), -Math.round(baseY + off * Math.sin(perpRad)));
- }
- }
- charInLine++;
- if (delay > 0) await sleep(delay);
- }
- }
- const hud = document.createElement('div');
- hud.id = "twow-gradient-hud";
- hud.style = `position:fixed; top:40px; left:10px; width:165px; background:rgba(26, 26, 26, 0.95); color:#aaa; border:1px solid #444; border-radius:8px; padding:8px; z-index:100000; font-family:sans-serif; box-shadow:0 10px 25px rgba(0,0,0,0.8);`;
- // CRITICAL FIX: zIndex in jscolor set to 100002 to be above the HUD (100000)
- hud.innerHTML = `
- <div id="drag" style="cursor:move; background:#252525; margin:-8px -8px 8px -8px; padding:6px; font-size:10px; display:flex; justify-content:space-between; border-radius:8px 8px 0 0; align-items:center;">
- <span style="font-weight:bold;">GRADIENT MAKER</span>
- <div><span id="menu-btn">⚙️</span><span id="close" style="cursor:pointer; color:#ff4d4d; margin-left:6px; font-weight:bold;">×</span></div>
- </div>
- <div id="view-main">
- <div class="hud-row">
- <input id="c1" data-jscolor="{zIndex:100002, onInput:'updateHUDPreview()'}" value="00FFCC" style="width:48%; height:22px; border-radius:4px; border:none; font-size:10px; text-align:center;">
- <input id="c2" data-jscolor="{zIndex:100002, onInput:'updateHUDPreview()'}" value="AA00FF" style="width:48%; height:22px; border-radius:4px; border:none; font-size:10px; text-align:center;">
- </div>
- <div class="hud-row"><span class="hud-label">TXT:</span><input id="gradText" type="text" placeholder="Text..." class="hud-input"></div>
- <div class="hud-row"><span class="hud-label">PAT:</span><select id="pat" class="hud-input"><option value="linear">LINEAR</option><option value="radial">RADIAL</option><option value="wave">WAVE</option><option value="zag">ZIGZAG</option><option value="spiral">SPIRAL</option></select></div>
- <div class="hud-row"><span class="hud-label">X:</span><input id="posX" type="number" value="146" class="hud-input"></div>
- <div class="hud-row"><span class="hud-label">Y:</span><input id="posY" type="number" value="-59" class="hud-input"></div>
- <div class="hud-row"><span class="hud-label">STP:</span><input id="stps" type="number" value="50" class="hud-input"></div>
- <div class="hud-row"><span class="hud-label">DEG:</span><input id="angle" type="number" value="0" class="hud-input"></div>
- <div class="hud-row"><span class="hud-label">WID:</span><input id="width" type="number" value="1" class="hud-input"></div>
- <div class="hud-row" style="margin-top:6px;"><span class="hud-label">SPD:</span><input id="speed" type="range" min="0" max="200" value="180" class="hud-slider"></div>
- <div style="display:flex; justify-content:space-between;">
- <button id="runBtn" class="btn-half">DRAW</button>
- <button id="rainBtn" class="btn-half" style="background:linear-gradient(90deg,red,orange,yellow,green,cyan,blue,violet);">RAIN</button>
- </div>
- </div>
- <div id="view-options" class="hidden">
- <div style="font-size:10px; font-weight:bold; margin-bottom:8px; border-bottom:1px solid #444; padding-bottom:4px;">SETTINGS</div>
- <div class="hud-row">Wrap At: <input id="opt-wrap" type="number" value="0" class="hud-input" style="width:40px;"></div>
- <div class="hud-row">Text Color: <input id="opt-text-color" type="color" value="#aaaaaa"></div>
- <div class="hud-row">Opacity: <input id="opt-opacity" type="range" min="20" max="100" value="95" class="hud-slider"></div>
- <button id="back-btn" style="width:100%; height:24px; background:#444; color:#fff; border:none; border-radius:4px; font-size:10px; margin-top:10px; cursor:pointer;">BACK</button>
- </div>
- `;
- document.body.appendChild(hud);
- // Logic
- const mainView = document.getElementById('view-main'), optionsView = document.getElementById('view-options');
- document.getElementById('menu-btn').onclick = () => { mainView.classList.toggle('hidden'); optionsView.classList.toggle('hidden'); };
- document.getElementById('back-btn').onclick = () => { mainView.classList.remove('hidden'); optionsView.classList.add('hidden'); };
- document.getElementById('opt-text-color').oninput = (e) => { hud.style.color = e.target.value; document.querySelectorAll('.hud-label').forEach(l => l.style.color = e.target.value); };
- document.getElementById('opt-opacity').oninput = (e) => { hud.style.background = `rgba(26, 26, 26, ${e.target.value / 100})`; };
- window.updateHUDPreview = function() {
- const c1 = document.getElementById('c1').value, c2 = document.getElementById('c2').value, angle = document.getElementById('angle').value;
- const h1 = c1.startsWith('#') ? c1 : '#' + c1, h2 = c2.startsWith('#') ? c2 : '#' + c2;
- document.getElementById('runBtn').style.background = `linear-gradient(${90 + parseInt(angle || 0)}deg, ${h1}, ${h2}, ${h1})`;
- };
- if (window.jscolor) window.jscolor.install();
- setTimeout(window.updateHUDPreview, 100);
- ['posX', 'posY', 'stps', 'angle', 'width'].forEach(id => document.getElementById(id)?.addEventListener('input', window.updateHUDPreview));
- document.getElementById('close').onclick = () => { hud.remove(); style.remove(); delete window.updateHUDPreview; };
- let isDragging = false, offset = [0,0];
- hud.onmousedown = (e) => { if(e.target.tagName === 'INPUT' || e.target.tagName === 'SELECT' || e.target.id === 'close' || e.target.type === 'range' || e.target.id === 'menu-btn') return; isDragging = true; offset = [hud.offsetLeft - e.clientX, hud.offsetTop - e.clientY]; };
- document.onmousemove = (e) => { if(!isDragging) return; hud.style.left = (e.clientX + offset[0])+'px'; hud.style.top = (e.clientY + offset[1])+'px'; };
- document.onmouseup = () => isDragging = false;
- const startDraw = async (rainbow) => {
- const c1 = document.getElementById('c1').value, c2 = document.getElementById('c2').value;
- const x = parseFloat(document.getElementById('posX').value), y = parseFloat(document.getElementById('posY').value);
- const steps = parseInt(document.getElementById('stps').value), angle = parseFloat(document.getElementById('angle').value);
- const width = parseInt(document.getElementById('width').value), delay = 200 - parseInt(document.getElementById('speed').value);
- const pattern = document.getElementById('pat').value, text = document.getElementById('gradText').value, wrap = parseInt(document.getElementById('opt-wrap').value);
- document.getElementById('runBtn').disabled = document.getElementById('rainBtn').disabled = true;
- await executeGradient([c1, c2, c1], steps, x, y, delay, angle, width, pattern, text, wrap, rainbow);
- document.getElementById('runBtn').disabled = document.getElementById('rainBtn').disabled = false;
- };
- document.getElementById('runBtn').onclick = () => startDraw(false);
- document.getElementById('rainBtn').onclick = () => startDraw(true);
- })();
Comments
-
- i told you to not feed it into an AI bro...
-
- agreed vibecoded scripts suc
-
- just learn coding already 🥀
Add Comment
Please, Sign In to add comment