smoothretro1982

Gradient Maker (update 8)

May 16th, 2026 (edited)
136
0
Never
3
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.99 KB | None | 0 0
  1. (function() {
  2. // 1. CSS
  3. const style = document.createElement('style');
  4. style.innerHTML = `
  5. #twow-gradient-hud input::-webkit-outer-spin-button,
  6. #twow-gradient-hud input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  7. #twow-gradient-hud input[type=number], #twow-gradient-hud select { -moz-appearance: textfield; text-align: center; }
  8. .hud-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; gap: 4px; }
  9. .hud-label { font-size: 9px; width: 30px; text-align: right; font-weight: bold; transition: color 0.3s; }
  10. .hud-input { background: #222; color: #fff; border: 1px solid #444; border-radius: 3px; padding: 3px; font-size: 11px; flex-grow: 1; width: 35px; }
  11. .hud-slider { flex-grow: 1; height: 4px; cursor: pointer; accent-color: #00FFCC; }
  12. .hidden { display: none !important; }
  13. #menu-btn { cursor: pointer; font-size: 12px; transition: transform 0.3s; }
  14. #menu-btn:hover { transform: rotate(45deg); color: #fff; }
  15. .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; }
  16. `;
  17. document.head.appendChild(style);
  18.  
  19. // Helpers
  20. const hexToRGB = (str) => {
  21. const hex = str.startsWith('#') ? str.slice(1) : str;
  22. const arr = [];
  23. for (let i = 0; i < 3; i++) arr.push(parseInt(hex.slice(i * 2, i * 2 + 2), 16) || 0);
  24. return arr;
  25. };
  26.  
  27. const hsvToRgb = (h, s, v) => {
  28. 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);
  29. switch (i % 6) {
  30. case 0: r = v, g = t, b = p; break;
  31. case 1: r = q, g = v, b = p; break;
  32. case 2: r = p, g = v, b = t; break;
  33. case 3: r = p, g = q, b = v; break;
  34. case 4: r = t, g = p, b = v; break;
  35. case 5: r = v, g = p, b = q; break;
  36. }
  37. return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
  38. };
  39.  
  40. const lerp = (a, b, t) => a + (b - a) * t;
  41. const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
  42.  
  43. async function executeGradient(cols, steps, startX, startY, delay, angleDeg, width, pattern, text, wrapLimit, isRainbow) {
  44. if (typeof writeCharAt !== 'function') return alert("writeCharAt missing!");
  45. const rgbCols = cols.map(hexToRGB);
  46. const angleRad = (angleDeg * Math.PI) / 180;
  47. const perpRad = angleRad + Math.PI / 2;
  48. const drawLimit = text.length > 0 ? text.length : steps;
  49. let lineOffset = 0, charInLine = 0;
  50.  
  51. for (let i = 0; i < drawLimit; i++) {
  52. if (wrapLimit > 0 && charInLine >= wrapLimit) { lineOffset++; charInLine = 0; }
  53. const progress = i / (drawLimit - 1 || 1);
  54.  
  55. let c;
  56. if (isRainbow) {
  57. c = hsvToRgb(progress, 1, 1);
  58. } else {
  59. const segmentProgress = progress * (rgbCols.length - 1);
  60. const index = Math.min(rgbCols.length - 2, Math.floor(segmentProgress));
  61. const t = segmentProgress % 1;
  62. 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))];
  63. }
  64.  
  65. const char = text.length > 0 ? text[i] : "█";
  66. let baseX = startX + charInLine * Math.cos(angleRad), baseY = startY + charInLine * Math.sin(angleRad);
  67. if (lineOffset > 0) { baseX += lineOffset * 1.5 * Math.cos(perpRad); baseY += lineOffset * 1.5 * Math.sin(perpRad); }
  68.  
  69. let patternOffset = 0;
  70. if (pattern === "wave") patternOffset = Math.sin(progress * Math.PI * 4) * 8;
  71. else if (pattern === "zag") patternOffset = (Math.abs(((progress * 4) % 1) - 0.5) * 4 - 1) * 8;
  72.  
  73. if (pattern === "radial" && text.length === 0) {
  74. const pts = i * 6;
  75. for (let p = 0; p < pts; p++) {
  76. const sA = (p / pts) * Math.PI * 2;
  77. writeCharAt(char, c, Math.round(startX + i * Math.cos(sA)), -Math.round(startY + i * Math.sin(sA)));
  78. }
  79. } else if (pattern === "spiral" && text.length === 0) {
  80. const rot = progress * Math.PI * 10;
  81. writeCharAt(char, c, Math.round(startX + i * Math.cos(rot)), -Math.round(startY + i * Math.sin(rot)));
  82. } else {
  83. const dW = text.length > 0 ? 1 : width;
  84. for (let w = 0; w < dW; w++) {
  85. const off = (w - Math.floor(dW / 2)) + patternOffset;
  86. writeCharAt(char, c, Math.round(baseX + off * Math.cos(perpRad)), -Math.round(baseY + off * Math.sin(perpRad)));
  87. }
  88. }
  89. charInLine++;
  90. if (delay > 0) await sleep(delay);
  91. }
  92. }
  93.  
  94. const hud = document.createElement('div');
  95. hud.id = "twow-gradient-hud";
  96. 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);`;
  97.  
  98. // CRITICAL FIX: zIndex in jscolor set to 100002 to be above the HUD (100000)
  99. hud.innerHTML = `
  100. <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;">
  101. <span style="font-weight:bold;">GRADIENT MAKER</span>
  102. <div><span id="menu-btn">⚙️</span><span id="close" style="cursor:pointer; color:#ff4d4d; margin-left:6px; font-weight:bold;">×</span></div>
  103. </div>
  104. <div id="view-main">
  105. <div class="hud-row">
  106. <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;">
  107. <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;">
  108. </div>
  109. <div class="hud-row"><span class="hud-label">TXT:</span><input id="gradText" type="text" placeholder="Text..." class="hud-input"></div>
  110. <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>
  111. <div class="hud-row"><span class="hud-label">X:</span><input id="posX" type="number" value="146" class="hud-input"></div>
  112. <div class="hud-row"><span class="hud-label">Y:</span><input id="posY" type="number" value="-59" class="hud-input"></div>
  113. <div class="hud-row"><span class="hud-label">STP:</span><input id="stps" type="number" value="50" class="hud-input"></div>
  114. <div class="hud-row"><span class="hud-label">DEG:</span><input id="angle" type="number" value="0" class="hud-input"></div>
  115. <div class="hud-row"><span class="hud-label">WID:</span><input id="width" type="number" value="1" class="hud-input"></div>
  116. <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>
  117. <div style="display:flex; justify-content:space-between;">
  118. <button id="runBtn" class="btn-half">DRAW</button>
  119. <button id="rainBtn" class="btn-half" style="background:linear-gradient(90deg,red,orange,yellow,green,cyan,blue,violet);">RAIN</button>
  120. </div>
  121. </div>
  122. <div id="view-options" class="hidden">
  123. <div style="font-size:10px; font-weight:bold; margin-bottom:8px; border-bottom:1px solid #444; padding-bottom:4px;">SETTINGS</div>
  124. <div class="hud-row">Wrap At: <input id="opt-wrap" type="number" value="0" class="hud-input" style="width:40px;"></div>
  125. <div class="hud-row">Text Color: <input id="opt-text-color" type="color" value="#aaaaaa"></div>
  126. <div class="hud-row">Opacity: <input id="opt-opacity" type="range" min="20" max="100" value="95" class="hud-slider"></div>
  127. <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>
  128. </div>
  129. `;
  130. document.body.appendChild(hud);
  131.  
  132. // Logic
  133. const mainView = document.getElementById('view-main'), optionsView = document.getElementById('view-options');
  134. document.getElementById('menu-btn').onclick = () => { mainView.classList.toggle('hidden'); optionsView.classList.toggle('hidden'); };
  135. document.getElementById('back-btn').onclick = () => { mainView.classList.remove('hidden'); optionsView.classList.add('hidden'); };
  136. 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); };
  137. document.getElementById('opt-opacity').oninput = (e) => { hud.style.background = `rgba(26, 26, 26, ${e.target.value / 100})`; };
  138.  
  139. window.updateHUDPreview = function() {
  140. const c1 = document.getElementById('c1').value, c2 = document.getElementById('c2').value, angle = document.getElementById('angle').value;
  141. const h1 = c1.startsWith('#') ? c1 : '#' + c1, h2 = c2.startsWith('#') ? c2 : '#' + c2;
  142. document.getElementById('runBtn').style.background = `linear-gradient(${90 + parseInt(angle || 0)}deg, ${h1}, ${h2}, ${h1})`;
  143. };
  144.  
  145. if (window.jscolor) window.jscolor.install();
  146. setTimeout(window.updateHUDPreview, 100);
  147. ['posX', 'posY', 'stps', 'angle', 'width'].forEach(id => document.getElementById(id)?.addEventListener('input', window.updateHUDPreview));
  148. document.getElementById('close').onclick = () => { hud.remove(); style.remove(); delete window.updateHUDPreview; };
  149.  
  150. let isDragging = false, offset = [0,0];
  151. 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]; };
  152. document.onmousemove = (e) => { if(!isDragging) return; hud.style.left = (e.clientX + offset[0])+'px'; hud.style.top = (e.clientY + offset[1])+'px'; };
  153. document.onmouseup = () => isDragging = false;
  154.  
  155. const startDraw = async (rainbow) => {
  156. const c1 = document.getElementById('c1').value, c2 = document.getElementById('c2').value;
  157. const x = parseFloat(document.getElementById('posX').value), y = parseFloat(document.getElementById('posY').value);
  158. const steps = parseInt(document.getElementById('stps').value), angle = parseFloat(document.getElementById('angle').value);
  159. const width = parseInt(document.getElementById('width').value), delay = 200 - parseInt(document.getElementById('speed').value);
  160. const pattern = document.getElementById('pat').value, text = document.getElementById('gradText').value, wrap = parseInt(document.getElementById('opt-wrap').value);
  161.  
  162. document.getElementById('runBtn').disabled = document.getElementById('rainBtn').disabled = true;
  163. await executeGradient([c1, c2, c1], steps, x, y, delay, angle, width, pattern, text, wrap, rainbow);
  164. document.getElementById('runBtn').disabled = document.getElementById('rainBtn').disabled = false;
  165. };
  166.  
  167. document.getElementById('runBtn').onclick = () => startDraw(false);
  168. document.getElementById('rainBtn').onclick = () => startDraw(true);
  169. })();
Comments
Add Comment
Please, Sign In to add comment