Created
December 20, 2025 13:04
-
-
Save EncodeTheCode/5fb17e1817c2da8a9db2ae4aa3e79626 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>Rogue Talent Mock</title> | |
| <style> | |
| body { | |
| margin:0; | |
| background:#0b1220; | |
| color:#e5e7eb; | |
| font-family:Arial, sans-serif; | |
| } | |
| canvas { | |
| display:block; | |
| background:#020617; | |
| } | |
| #hud { | |
| position:absolute; | |
| top:10px; | |
| left:10px; | |
| background:rgba(0,0,0,.6); | |
| padding:8px; | |
| border-radius:6px; | |
| } | |
| #talentOverlay { | |
| position:fixed; | |
| inset:0; | |
| background:rgba(0,0,0,.7); | |
| display:none; | |
| justify-content:center; | |
| align-items:center; | |
| } | |
| #talentWindow { | |
| width:1000px; | |
| height:600px; | |
| background:#020617; | |
| border-radius:10px; | |
| display:flex; | |
| gap:10px; | |
| padding:10px; | |
| } | |
| .tree { | |
| flex:1; | |
| background:#020617; | |
| border:1px solid #1e293b; | |
| border-radius:8px; | |
| padding:8px; | |
| } | |
| .tree h3 { margin:4px 0; text-align:center; } | |
| .tree .points { text-align:center; color:#38bdf8; } | |
| .grid { | |
| display:grid; | |
| grid-template-columns:repeat(3,1fr); | |
| grid-template-rows:repeat(5,1fr); | |
| gap:6px; | |
| margin-top:6px; | |
| } | |
| .node { | |
| background:#020617; | |
| border:1px solid #1e293b; | |
| border-radius:6px; | |
| padding:4px; | |
| font-size:12px; | |
| text-align:center; | |
| } | |
| .node.locked { opacity:.35 } | |
| .node .count { font-size:11px; color:#38bdf8 } | |
| .node button { | |
| background:#020617; | |
| color:#e5e7eb; | |
| border:1px solid #1e293b; | |
| cursor:pointer; | |
| margin:2px; | |
| } | |
| .node button:disabled { opacity:.3; cursor:not-allowed } | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="game" width="900" height="600"></canvas> | |
| <div id="hud">WASD move · Mouse aim · Press <b>K</b> for talents</div> | |
| <div id="talentOverlay"> | |
| <div id="talentWindow"></div> | |
| </div> | |
| <script> | |
| /* ===================== | |
| GAME (PLAYER + AIM) | |
| ===================== */ | |
| const canvas = document.getElementById("game"); | |
| const ctx = canvas.getContext("2d"); | |
| const player = { x:450, y:300, speed:200, ax:450, ay:300 }; | |
| const keys = {}; | |
| window.addEventListener("keydown",e=>keys[e.key]=true); | |
| window.addEventListener("keyup",e=>keys[e.key]=false); | |
| canvas.addEventListener("mousemove",e=>{ | |
| const r=canvas.getBoundingClientRect(); | |
| player.ax=e.clientX-r.left; | |
| player.ay=e.clientY-r.top; | |
| }); | |
| let last=performance.now(); | |
| function loop(t){ | |
| const dt=(t-last)/1000; last=t; | |
| let dx=0,dy=0; | |
| if(keys.w)dy--; if(keys.s)dy++; | |
| if(keys.a)dx--; if(keys.d)dx++; | |
| if(dx||dy){ | |
| const l=Math.hypot(dx,dy); dx/=l; dy/=l; | |
| player.x+=dx*player.speed*dt; | |
| player.y+=dy*player.speed*dt; | |
| } | |
| ctx.clearRect(0,0,900,600); | |
| ctx.beginPath(); | |
| ctx.moveTo(player.x,player.y); | |
| ctx.lineTo(player.ax,player.ay); | |
| ctx.strokeStyle="#000"; ctx.lineWidth=3; ctx.stroke(); | |
| ctx.beginPath(); | |
| ctx.arc(player.x,player.y,14,0,Math.PI*2); | |
| ctx.fillStyle="#38bdf8"; ctx.fill(); | |
| requestAnimationFrame(loop); | |
| } | |
| requestAnimationFrame(loop); | |
| /* ===================== | |
| TALENT SYSTEM | |
| ===================== */ | |
| const TOTAL_POINTS = 51; | |
| const TIER_REQ = [0,5,10,15,20]; | |
| let available = TOTAL_POINTS; | |
| const trees = ["Stalker","Duelist","Nightblade"].map(name=>({ | |
| name, | |
| talents:[], | |
| })); | |
| trees.forEach(tree=>{ | |
| for(let r=0;r<5;r++){ | |
| for(let c=0;c<3;c++){ | |
| tree.talents.push({ | |
| row:r, | |
| name:`${tree.name} Talent`, | |
| max:(r===0&&c===1)?3:1, | |
| spent:0 | |
| }); | |
| } | |
| } | |
| }); | |
| const overlay=document.getElementById("talentOverlay"); | |
| const windowEl=document.getElementById("talentWindow"); | |
| function pointsInTree(t){ | |
| return t.talents.reduce((s,x)=>s+x.spent,0); | |
| } | |
| function buildUI(){ | |
| windowEl.innerHTML=""; | |
| trees.forEach(tree=>{ | |
| const div=document.createElement("div"); | |
| div.className="tree"; | |
| const pts=pointsInTree(tree); | |
| div.innerHTML=`<h3>${tree.name}</h3> | |
| <div class="points">${pts} pts</div>`; | |
| const grid=document.createElement("div"); | |
| grid.className="grid"; | |
| tree.talents.forEach(t=>{ | |
| const unlocked = pts >= TIER_REQ[t.row]; | |
| const n=document.createElement("div"); | |
| n.className="node"+(unlocked?"":" locked"); | |
| n.innerHTML=`<div>${t.name}</div> | |
| <div class="count">${t.spent}/${t.max}</div>`; | |
| const plus=document.createElement("button"); | |
| plus.textContent="+"; | |
| plus.disabled=!unlocked||t.spent>=t.max||available<=0; | |
| plus.onclick=()=>{ | |
| t.spent++; available--; buildUI(); | |
| }; | |
| const minus=document.createElement("button"); | |
| minus.textContent="-"; | |
| minus.disabled=t.spent<=0||pointsInTree(tree)-1<TIER_REQ[t.row]; | |
| minus.onclick=()=>{ | |
| t.spent--; available++; buildUI(); | |
| }; | |
| n.append(plus,minus); | |
| grid.appendChild(n); | |
| }); | |
| div.appendChild(grid); | |
| windowEl.appendChild(div); | |
| }); | |
| } | |
| buildUI(); | |
| /* ===================== | |
| TOGGLE TALENTS | |
| ===================== */ | |
| let open=false; | |
| window.addEventListener("keydown",e=>{ | |
| if(e.key.toLowerCase()==="k"){ | |
| open=!open; | |
| overlay.style.display=open?"flex":"none"; | |
| buildUI(); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment