11.8.26

SoccerNet Free Hotspot Login

 Berikut adalah login page untuk Hotspot Mikrotik sederhana, pembuatannya dibantu AI, khususnya untuk gambar dan efek bola. Simpan sebagai login.html menggantikan login.html halaman default.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SoccerNet</title>
    <style>
        *{margin:0;padding:0;box-sizing:border-box}
        body{
            min-height:100vh;
            display:flex;flex-direction:column;align-items:center;justify-content:center;
            background:#080c0a;
            background:radial-gradient(ellipse at 50% 100%,#101e16 0%,#080c0a 55%);
            font-family:-apple-system,'Segoe UI',Helvetica,sans-serif;
            color:rgba(255,255,255,.85);overflow:hidden;user-select:none;-webkit-user-select:none;
        }
        .brand{display:flex;flex-direction:column;align-items:center;margin-bottom:1.6rem}
        #ball{
            width:120px;height:120px;cursor:grab;
            filter:drop-shadow(0 6px 18px rgba(0,0,0,.5));
            margin-bottom:1rem;
        }
        #ball:active{cursor:grabbing}
        .title{font-size:1.65rem;font-weight:700;letter-spacing:.05em;color:#fff}
        .title b{color:#2d8a4e;font-weight:700}
        .card{
            width:100%;max-width:330px;
            padding:1.8rem 2rem 1.4rem;
            background:rgba(255,255,255,.025);
            border:1px solid rgba(255,255,255,.06);
            border-radius:14px;
            backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);
        }
        .err{
            display:none;
            background:rgba(220,60,50,.08);
            border:1px solid rgba(220,60,50,.22);
            color:#d9604f;font-size:.8rem;
            padding:.55rem .85rem;border-radius:8px;
            margin-bottom:1.1rem;text-align:center;line-height:1.4;
        }
        .field{margin-bottom:.95rem}
        .field label{
            display:block;font-size:.7rem;font-weight:600;
            color:rgba(255,255,255,.38);text-transform:uppercase;
            letter-spacing:.12em;margin-bottom:.35rem;
        }
        .field input{
            width:100%;padding:.65rem 0;
            background:transparent;border:none;
            border-bottom:1.5px solid rgba(255,255,255,.1);
            color:#fff;font-size:.92rem;font-family:inherit;outline:none;
            transition:border-color .25s;
        }
        .field input:focus{border-bottom-color:#2d8a4e}
        .field input::placeholder{color:rgba(255,255,255,.18)}
        .btn{
            width:100%;padding:.72rem;margin-top:.5rem;
            background:#2d8a4e;color:#fff;border:none;border-radius:9px;
            font-size:.88rem;font-weight:600;font-family:inherit;
            letter-spacing:.04em;cursor:pointer;
            transition:background .2s,transform .12s;
        }
        .btn:hover{background:#35a15b}
        .btn:active{transform:scale(.98)}
        .foot{
            margin-top:1.8rem;text-align:center;
            font-size:.65rem;color:rgba(255,255,255,.16);line-height:1.7;
        }
        /* Subtle ground line */
        .gnd{
            width:100px;height:1px;margin-top:-4px;
            background:linear-gradient(90deg,transparent,rgba(255,255,255,.04),transparent);
        }
    </style>
</head>
<body>
<div class="brand">
    <svg id="ball" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg"></svg>
    <div class="gnd"></div>
    <h1 class="title">Soccer<b>Net</b></h1>
</div>
<form name="sendin" action="$(link-login-only)" method="post" onsubmit="return doLogin()">
    <input type="hidden" name="dst" value="$(link-orig)" />
    <input type="hidden" name="popup" value="true" />
    <div class="card">
        <div class="err" $(if error)style="display:block"$(endif)>$(error)</div>
        <div class="field">
            <label for="un">Username</label>
            <input type="text" id="un" name="username" value="$(username)" placeholder="Enter username" autofocus />
        </div>
        <div class="field">
            <label for="pw">Password</label>
            <input type="password" id="pw" name="password" placeholder="Enter password" />
        </div>
        <button type="submit" class="btn">Login</button>
    </div>
</form>
<div class="foot">
    MAC: $(mac) &middot; IP: $(ip)
</div>
<script>
/* ===== Mikrotik hotspot submit ===== */
function doLogin(){document.sendin.submit();return false}
/* ===== Truncated Icosahedron Soccer Ball ===== */
(function(){
    var PHI=(1+Math.sqrt(5))/2, CX=200,CY=200,RAD=147;
    var raw=[];
    var a,b,c,i;
    for(a=-1;a<=1;a+=2)for(b=-1;b<=1;b+=2){
        raw.push([0,a,b*3*PHI]);
        raw.push([a,b*3*PHI,0]);
        raw.push([b*3*PHI,0,a]);
    }
    for(a=-1;a<=1;a+=2)for(b=-1;b<=1;b+=2)for(c=-1;c<=1;c+=2){
        raw.push([a*2,b*(1+2*PHI),c*PHI]);
        raw.push([b*(1+2*PHI),c*PHI,a*2]);
        raw.push([c*PHI,a*2,b*(1+2*PHI)]);
    }
    for(a=-1;a<=1;a+=2)for(b=-1;b<=1;b+=2)for(c=-1;c<=1;c+=2){
        raw.push([a,b*(2+PHI),c*2*PHI]);
        raw.push([b*(2+PHI),c*2*PHI,a]);
        raw.push([c*2*PHI,a,b*(2+PHI)]);
    }
    var NS=Math.sqrt(10+9*PHI);
    var V=raw.map(function(v){return[v[0]/NS,v[1]/NS,v[2]/NS]});
    /* Edges */
    var EL2=4/(NS*NS), NB=[];
    for(i=0;i<60;i++) NB[i]=[];
    for(i=0;i<60;i++)for(var j=i+1;j<60;j++){
        var dx=V[i][0]-V[j][0],dy=V[i][1]-V[j][1],dz=V[i][2]-V[j][2];
        if(Math.abs(dx*dx+dy*dy+dz*dz-EL2)<0.001){NB[i].push(j);NB[j].push(i)}
    }
    /* Helpers */
    function cr(a,b,c){
        var e1x=V[b][0]-V[a][0],e1y=V[b][1]-V[a][1],e1z=V[b][2]-V[a][2];
        var e2x=V[c][0]-V[b][0],e2y=V[c][1]-V[b][1],e2z=V[c][2]-V[b][2];
        return[e1y*e2z-e1z*e2y,e1z*e2x-e1x*e2z,e1x*e2y-e1y*e2x];
    }
    function dt(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]}
    function cn(a,b,c){return[(V[a][0]+V[b][0]+V[c][0])/3,(V[a][1]+V[b][1]+V[c][1])/3,(V[a][2]+V[b][2]+V[c][2])/3]}
    /* Face tracing */
    var seen={}, faces=[];
    for(i=0;i<60;i++)for(var _j=0;_j<NB[i].length;_j++){
        var w=NB[i][_j];
        if(seen[i+'-'+w])continue;
        var face=[i],p=i,cc=w;
        while(true){
            seen[p+'-'+cc]=true;
            face.push(cc);
            var cands=NB[cc].filter(function(n){return n!==p});
            var best=-1,bestD=-1e9;
            for(var k=0;k<cands.length;k++){
                var d=dt(cr(p,cc,cands[k]),cn(p,cc,cands[k]));
                if(d>bestD){bestD=d;best=cands[k]}
            }
            if(best<0)break;
            p=cc;cc=best;
            if(cc===i)break;
            if(face.length>10)break;
        }
        if(face.length===5||face.length===6)faces.push(face);
    }
    /* Initial rotation: put a pentagon facing viewer */
    var topZ=-1e9,topC=null;
    for(i=0;i<faces.length;i++){
        var f=faces[i]; if(f.length!==5)continue;
        var cz=0;for(j=0;j<5;j++)cz+=V[f[j]][2]; cz/=5;
        if(cz>topZ){
            topZ=cz;
            topC=[0,0,0];
            for(j=0;j<5;j++){topC[0]+=V[f[j]][0];topC[1]+=V[f[j]][1];topC[2]+=V[f[j]][2]}
            topC[0]/=5;topC[1]/=5;topC[2]/=5;
        }
    }
    var iRY=Math.atan2(-topC[0],topC[2]);
    var iRX=Math.atan2(topC[1],Math.sqrt(topC[0]*topC[0]+topC[2]*topC[2]));
    function rot(x,y,z,rx,ry){
        var cY=Math.cos(ry),sY=Math.sin(ry);
        var x1=x*cY+z*sY,z1=-x*sY+z*cY;
        var cX=Math.cos(rx),sX=Math.sin(rx);
        return[x1,y*cX-z1*sX,y*sX+z1*cX];
    }
    var svg=document.getElementById('ball');
    function draw(rx,ry){
        var P=V.map(function(v){var t=rot(v[0],v[1],v[2],rx,ry);
            return{sx:CX+t[0]*RAD,sy:CY-t[1]*RAD,z:t[2]}});
        var rf=faces.map(function(f){
            var pts=f.map(function(ii){return P[ii]});
            var az=0;for(var k=0;k<pts.length;k++)az+=pts[k].z;az/=pts.length;
            return{pts:pts,az:az,pent:f.length===5};
        });
        rf.sort(function(a,b){return a.az-b.az});
        var s='<defs>';
        s+='<clipPath id="bc"><circle cx="'+CX+'" cy="'+CY+'" r="'+RAD+'"/></clipPath>';
        s+='<radialGradient id="sh" cx="34%" cy="28%" r="66%">';
        s+='<stop offset="0%" stop-color="rgba(255,255,255,0.12)"/>';
        s+='<stop offset="45%" stop-color="rgba(0,0,0,0)"/>';
        s+='<stop offset="100%" stop-color="rgba(0,0,0,0.55)"/>';
        s+='</radialGradient>';
        s+='<radialGradient id="sp" cx="35%" cy="26%" r="16%">';
        s+='<stop offset="0%" stop-color="rgba(255,255,255,0.5)"/>';
        s+='<stop offset="100%" stop-color="rgba(255,255,255,0)"/>';
        s+='</radialGradient></defs>';
        s+='<circle cx="'+CX+'" cy="'+CY+'" r="'+RAD+'" fill="#edecea"/>';
        s+='<g clip-path="url(#bc)">';
        for(i=0;i<rf.length;i++){
            var ff=rf[i],d='';
            for(var k=0;k<ff.pts.length;k++){
                d+=(k?'L':'M')+ff.pts[k].sx.toFixed(1)+','+ff.pts[k].sy.toFixed(1);
            }
            d+='Z';
            if(ff.pent){
                s+='<path d="'+d+'" fill="#1a1a1c" stroke="#0e0e10" stroke-width="0.8" stroke-linejoin="round"/>';
            }else{
                s+='<path d="'+d+'" fill="#edecea" stroke="#c8c5b9" stroke-width="0.5" stroke-linejoin="round"/>';
            }
        }
        s+='</g>';
        s+='<circle cx="'+CX+'" cy="'+CY+'" r="'+RAD+'" fill="url(#sh)"/>';
        s+='<circle cx="'+CX+'" cy="'+CY+'" r="'+RAD+'" fill="url(#sp)"/>';
        svg.innerHTML=s;
    }
    var rx=iRX,ry=iRY,drag=false,lx=0,ly=0,lastT=0,idleT=0,lastPh=-1;
    function pD(x,y){drag=true;lx=x;ly=y;lastT=performance.now()}
    function pM(x,y){if(!drag)return;ry+=(x-lx)*.007;rx+=(y-ly)*.007;
        rx=Math.max(-1.3,Math.min(1.3,rx));lx=x;ly=y;lastT=performance.now();draw(rx,ry)}
    function pU(){drag=false}
    svg.addEventListener('mousedown',function(e){e.preventDefault();pD(e.clientX,e.clientY)});
    window.addEventListener('mousemove',function(e){pM(e.clientX,e.clientY)});
    window.addEventListener('mouseup',pU);
    svg.addEventListener('touchstart',function(e){e.preventDefault();var t=e.touches[0];pD(t.clientX,t.clientY)},{passive:false});
    window.addEventListener('touchmove',function(e){if(!drag)return;var t=e.touches[0];pM(t.clientX,t.clientY)},{passive:true});
    window.addEventListener('touchend',pU);
    function loop(t){
        requestAnimationFrame(loop);
        if(drag)return;
        if(t-lastT<2500)return;
        idleT+=0.003;
        var ph=Math.round(idleT*60);
        if(ph===lastPh)return;lastPh=ph;
        draw(rx+Math.sin(idleT*.5)*.04, ry+idleT*.09);
    }
    draw(rx,ry);
    requestAnimationFrame(loop);
})();
</script>
</body>
</html>

Berikut adalah preview-nya:

 Preview