Created
December 20, 2025 13:23
-
-
Save EncodeTheCode/b0507b1d94657c537c77187e529b1d98 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>WoW-Style Rogue Talent Mock</title> | |
| <style> | |
| body { margin:0; background:#081018; color:#e6eef6; font-family:Arial } | |
| canvas { background:#0b1324; display:block; margin:10px auto; border-radius:8px } | |
| .overlay { position:fixed; inset:0; background:rgba(0,0,0,.6); display:none; align-items:center; justify-content:center } | |
| .window { background:#0e1628; padding:16px; width:1000px; border-radius:12px; display:flex; gap:12px } | |
| .tree { flex:1; background:#0b1220; padding:10px; border-radius:8px } | |
| .grid { display:grid; grid-template-columns:repeat(3,1fr); grid-template-rows:repeat(6,70px); gap:8px; margin-top:8px } | |
| .node { background:#121a30; border-radius:8px; position:relative; cursor:pointer; padding:6px; text-align:center } | |
| .node.locked { opacity:.35; cursor:not-allowed } | |
| .count { position:absolute; top:4px; right:6px; font-size:11px } | |
| button { background:#1e293b; color:white; border:none; padding:4px 8px; border-radius:6px; cursor:pointer } | |
| button:disabled { opacity:.3 } | |
| h3 { margin:0 } | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="game" width="900" height="500"></canvas> | |
| <div class="overlay" id="overlay"> | |
| <div class="window"> | |
| <div class="tree"><h3>Stalker</h3><div id="grid0" class="grid"></div></div> | |
| <div class="tree"><h3>Duelist</h3><div id="grid1" class="grid"></div></div> | |
| <div class="tree"><h3>Nightblade</h3><div id="grid2" class="grid"></div></div> | |
| </div> | |
| </div> | |
| <script> | |
| /* ========================= | |
| TALENT SYSTEM (FIXED) | |
| ========================= */ | |
| const TOTAL_POINTS = 51; | |
| let available = TOTAL_POINTS; | |
| const trees = []; | |
| const ROWS = 6, COLS = 3; | |
| // Build trees | |
| for (let t = 0; t < 3; t++) { | |
| const talents = []; | |
| for (let r = 0; r < ROWS; r++) { | |
| for (let c = 0; c < COLS; c++) { | |
| talents.push({ | |
| id:`t${t}_${r}_${c}`, | |
| row:r, | |
| col:c, | |
| spent:0, | |
| max:(c === 1 ? 2 : 1) // center talents are multi-rank | |
| }); | |
| } | |
| } | |
| trees.push(talents); | |
| } | |
| // Points in tree | |
| function pointsInTree(t) { | |
| return trees[t].reduce((s,x)=>s+x.spent,0); | |
| } | |
| // WoW-style tier unlock (FIX) | |
| function isRowUnlocked(tree,row) { | |
| return pointsInTree(tree) >= row * 5; | |
| } | |
| // Spend point | |
| function spend(tree,id) { | |
| if (available <= 0) return; | |
| const t = trees[tree].find(x=>x.id===id); | |
| if (!t || t.spent >= t.max) return; | |
| if (!isRowUnlocked(tree,t.row)) return; | |
| t.spent++; | |
| available--; | |
| render(); | |
| } | |
| // Reset function (required by you) | |
| window.reset_talents = function() { | |
| if (!confirm("Reset all talents?")) return; | |
| trees.flat().forEach(t=>t.spent=0); | |
| available = TOTAL_POINTS; | |
| render(); | |
| }; | |
| // Render UI | |
| function render() { | |
| for (let ti = 0; ti < 3; ti++) { | |
| const grid = document.getElementById(`grid${ti}`); | |
| grid.innerHTML = ""; | |
| trees[ti].forEach(t => { | |
| const node = document.createElement("div"); | |
| node.className = "node"; | |
| if (!isRowUnlocked(ti,t.row)) node.classList.add("locked"); | |
| node.innerHTML = ` | |
| <div class="count">${t.spent}/${t.max}</div> | |
| Tier ${t.row+1} | |
| <br><button ${(!isRowUnlocked(ti,t.row)||t.spent>=t.max)?"disabled":""}>+</button> | |
| `; | |
| node.querySelector("button").onclick = ()=>spend(ti,t.id); | |
| grid.appendChild(node); | |
| }); | |
| } | |
| } | |
| render(); | |
| /* ========================= | |
| GAME (MOVEMENT + AIM) | |
| ========================= */ | |
| const canvas = document.getElementById("game"); | |
| const ctx = canvas.getContext("2d"); | |
| const p = {x:450,y:250}; | |
| const keys = {}; | |
| let mx=450,my=250; | |
| window.onkeydown=e=>{keys[e.key]=true;if(e.key==="k")toggle()}; | |
| window.onkeyup=e=>keys[e.key]=false; | |
| canvas.onmousemove=e=>{ | |
| const r=canvas.getBoundingClientRect(); | |
| mx=e.clientX-r.left; my=e.clientY-r.top; | |
| }; | |
| function toggle(){ | |
| const o=document.getElementById("overlay"); | |
| o.style.display=o.style.display==="flex"?"none":"flex"; | |
| } | |
| function loop(){ | |
| if(keys.w)p.y-=3;if(keys.s)p.y+=3;if(keys.a)p.x-=3;if(keys.d)p.x+=3; | |
| ctx.clearRect(0,0,canvas.width,canvas.height); | |
| ctx.beginPath(); ctx.moveTo(p.x,p.y); ctx.lineTo(mx,my); ctx.strokeStyle="#000"; ctx.lineWidth=3; ctx.stroke(); | |
| ctx.beginPath(); ctx.arc(p.x,p.y,14,0,Math.PI*2); ctx.fillStyle="#2ea3ff"; ctx.fill(); | |
| requestAnimationFrame(loop); | |
| } | |
| loop(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment