From e33874557930a54656b35c50c8178727aabfb337 Mon Sep 17 00:00:00 2001 From: levouinse Date: Thu, 19 Feb 2026 18:07:16 +0800 Subject: [PATCH] add skeleton loading, tutorial, and mobile support for head move --- index.html | 455 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 452 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 9589cfc..369c5fa 100644 --- a/index.html +++ b/index.html @@ -110,12 +110,181 @@ } .hide-ui-elements{top:60px;left:20px} .hidden{display:none} + + /* ═══════════════════════════════════════════════════════ + QUICK START TUTORIAL + ═══════════════════════════════════════════════════════ */ + .tutorial-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(10,10,15,0.95);backdrop-filter:blur(8px);z-index:10000;display:none;align-items:center;justify-content:center} + .tutorial-overlay.active{display:flex} + .tutorial-card{background:rgba(10,10,20,0.95);border:2px solid rgba(100,220,255,0.3);border-radius:12px;padding:32px;max-width:500px;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,0.5)} + .tutorial-title{font-family:'Space Grotesk',sans-serif;font-size:24px;color:#64dcff;margin-bottom:16px;letter-spacing:1px} + .tutorial-text{font-size:14px;color:#c0c0cc;line-height:1.8;margin-bottom:24px} + .tutorial-step{font-size:12px;color:#808090;margin-bottom:20px} + .tutorial-highlight{color:#64dcff;font-weight:600;background:rgba(100,220,255,0.1);padding:2px 8px;border-radius:4px} + .tutorial-btn{background:linear-gradient(135deg,#64dcff,#a78bfa);border:none;color:#0a0a0f;padding:12px 32px;border-radius:6px;font-family:'JetBrains Mono',monospace;font-size:13px;font-weight:600;cursor:pointer;letter-spacing:0.5px;transition:transform 0.2s} + .tutorial-btn:hover{transform:scale(1.05)} + .tutorial-skip{margin-top:16px;font-size:11px;color:#606070;cursor:pointer;text-decoration:underline} + .tutorial-skip:hover{color:#64dcff} + .tutorial-progress{display:flex;gap:8px;justify-content:center;margin-top:20px} + .tutorial-dot{width:8px;height:8px;border-radius:50%;background:rgba(100,220,255,0.2);transition:all 0.3s} + .tutorial-dot.active{background:#64dcff;width:24px;border-radius:4px} + + /* ═══════════════════════════════════════════════════════ + MOBILE VIRTUAL JOYSTICK + ═══════════════════════════════════════════════════════ */ + .mobile-controls{position:fixed;bottom:20px;left:0;right:0;display:none;justify-content:space-between;padding:0 20px;pointer-events:none;z-index:100} + @media(max-width:768px){.mobile-controls{display:flex}} + .joystick-container{width:120px;height:120px;position:relative;pointer-events:auto} + .joystick-base{width:100%;height:100%;border-radius:50%;background:rgba(10,10,20,0.6);backdrop-filter:blur(8px);border:2px solid rgba(100,220,255,0.3);position:relative} + .joystick-stick{width:50px;height:50px;border-radius:50%;background:linear-gradient(135deg,#64dcff,#a78bfa);position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);box-shadow:0 4px 12px rgba(100,220,255,0.4);transition:all 0.1s} + .joystick-label{position:absolute;top:-25px;left:50%;transform:translateX(-50%);font-size:10px;color:#64dcff;font-family:'JetBrains Mono',monospace;white-space:nowrap} + .mobile-btn-group{display:flex;flex-direction:column;gap:12px;pointer-events:auto} + .mobile-btn{width:60px;height:60px;border-radius:50%;background:rgba(10,10,20,0.6);backdrop-filter:blur(8px);border:2px solid rgba(100,220,255,0.3);display:flex;align-items:center;justify-content:center;font-size:11px;color:#64dcff;font-family:'JetBrains Mono',monospace;font-weight:600;touch-action:none;user-select:none} + .mobile-btn.active{background:rgba(100,220,255,0.3);border-color:#64dcff;box-shadow:0 0 20px rgba(100,220,255,0.5)} + + /* ═══════════════════════════════════════════════════════ + PHONEME SELECTOR + ═══════════════════════════════════════════════════════ */ + .phoneme-panel{position:absolute;bottom:20px;right:20px;background:rgba(10,10,20,0.85);backdrop-filter:blur(12px);border:1px solid rgba(100,220,255,0.15);border-radius:8px;padding:14px;pointer-events:auto;display:none} + @media(max-width:768px){.phoneme-panel{bottom:160px;right:10px}} + .phoneme-panel.visible{display:block} + .phoneme-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px} + .phoneme-btn{width:50px;height:50px;border-radius:8px;background:rgba(167,139,250,0.1);border:1px solid rgba(167,139,250,0.3);color:#a78bfa;font-family:'Space Grotesk',sans-serif;font-size:20px;font-weight:600;cursor:pointer;transition:all 0.2s;display:flex;align-items:center;justify-content:center} + .phoneme-btn:hover{background:rgba(167,139,250,0.25);border-color:#a78bfa;transform:scale(1.1)} + .phoneme-btn.active{background:rgba(167,139,250,0.3);border-color:#a78bfa;box-shadow:0 0 16px rgba(167,139,250,0.5)} + .phoneme-toggle{position:absolute;top:20px;right:380px;background:rgba(10,10,20,0.85);backdrop-filter:blur(12px);border:1px solid rgba(100,220,255,0.15);border-radius:6px;padding:6px 14px;color:#a78bfa;font-family:'JetBrains Mono',monospace;font-size:10px;cursor:pointer;pointer-events:auto;z-index:20} + .phoneme-toggle:hover{background:rgba(167,139,250,0.15)} + @media(max-width:768px){.phoneme-toggle{top:10px;right:10px}} + + /* ═══════════════════════════════════════════════════════ + SKELETON LOADING + ═══════════════════════════════════════════════════════ */ + .skeleton-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:#0a0a0f;z-index:9999;display:flex;align-items:center;justify-content:center;opacity:1;transition:opacity 0.4s ease} + .skeleton-overlay.fade-out{opacity:0;pointer-events:none} + .skeleton-container{width:90%;max-width:1400px;height:90vh;display:grid;grid-template-columns:1fr 2fr 1fr;grid-template-rows:auto 1fr auto;gap:20px;padding:20px} + + /* Skeleton shimmer animation */ + @keyframes shimmer{0%{background-position:-1000px 0}100%{background-position:1000px 0}} + .skeleton-box{background:linear-gradient(90deg,rgba(100,220,255,0.03) 0%,rgba(100,220,255,0.08) 50%,rgba(100,220,255,0.03) 100%);background-size:1000px 100%;animation:shimmer 2s infinite linear;border:1px solid rgba(100,220,255,0.1);border-radius:8px;position:relative;overflow:hidden} + .skeleton-box::after{content:'';position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient(90deg,transparent 0%,rgba(100,220,255,0.15) 50%,transparent 100%);animation:shimmer 2s infinite linear} + + /* Header skeleton */ + .skeleton-header{grid-column:1/4;height:60px;display:flex;align-items:center;padding:0 20px;gap:12px} + .skeleton-logo{width:24px;height:24px;border-radius:4px;background:rgba(100,220,255,0.15)} + .skeleton-title{flex:1;height:20px;max-width:300px;border-radius:4px} + + /* Left panel (controls) */ + .skeleton-left{grid-column:1;grid-row:2;display:flex;flex-direction:column;gap:20px} + .skeleton-panel{padding:18px;display:flex;flex-direction:column;gap:12px} + .skeleton-panel-header{height:14px;width:60%;border-radius:3px;background:rgba(100,220,255,0.2);margin-bottom:8px} + .skeleton-row{height:28px;border-radius:4px;background:rgba(100,220,255,0.05)} + .skeleton-row.tall{height:40px} + .skeleton-row.short{height:20px;width:70%} + + /* Center canvas */ + .skeleton-canvas{grid-column:2;grid-row:1/4;background:radial-gradient(circle at center,rgba(100,220,255,0.05) 0%,transparent 70%);border:1px solid rgba(100,220,255,0.08);border-radius:12px;position:relative} + .skeleton-canvas::before{content:'';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:120px;height:120px;border:3px solid rgba(100,220,255,0.2);border-top-color:#64dcff;border-radius:50%;animation:spin 1.5s linear infinite} + @keyframes spin{to{transform:translate(-50%,-50%) rotate(360deg)}} + .skeleton-canvas-text{position:absolute;bottom:30px;left:50%;transform:translateX(-50%);font-size:11px;color:rgba(100,220,255,0.5);font-family:'JetBrains Mono',monospace;letter-spacing:1px} + + /* Right panel (model) */ + .skeleton-right{grid-column:3;grid-row:2;display:flex;flex-direction:column;gap:20px} + .skeleton-button{height:36px;border-radius:6px;background:rgba(100,220,255,0.08);border:1px solid rgba(100,220,255,0.15)} + .skeleton-dropzone{height:80px;border:2px dashed rgba(100,220,255,0.15);border-radius:6px;background:rgba(100,220,255,0.02)} + + /* Footer skeleton */ + .skeleton-footer{grid-column:1/4;height:100px;display:flex;gap:20px} + .skeleton-footer-panel{flex:1;padding:18px} + + /* Mobile responsive */ + @media(max-width:768px){ + .skeleton-container{grid-template-columns:1fr;grid-template-rows:auto auto 1fr auto;gap:12px;padding:12px} + .skeleton-header{grid-column:1;height:50px} + .skeleton-left{grid-column:1;grid-row:2} + .skeleton-canvas{grid-column:1;grid-row:3;min-height:300px} + .skeleton-right{grid-column:1;grid-row:4} + .skeleton-footer{grid-column:1;grid-row:5;flex-direction:column;height:auto} + } + + +
+
+
Welcome to Discord ID Bypass
+
Let's get you started in 3 simple steps
+
+ +
Skip tutorial
+
+
+
+ + +
+
+ +
+ +
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
INITIALIZING THREE.JS
+
+ + +
+
+
+
+
+
+
+
+
+ + + +
+
+
+
Discord ID Bypass Tool by PromptPirate
@@ -223,6 +392,33 @@
Right-click drag to orbit · Scroll to zoom
+ + +
+
+ + + + + + +
+
+
+ + +
+
+
HEAD
+
+
+
+
+
+
MOUTH
+
ROLL L
+
ROLL R
+
@@ -234,10 +430,11 @@ // CONFIG & STATE // ═══════════════════════════════════════════════════════ var CFG={hS:1,mS:1,mRange:1.0,yawMax:80,pitchMax:50,rollMax:35,dz:0.12,sm:0.12,msm:0.15,jawAxis:'x',jawDir:1,jawAngle:0.4}; -var S={tY:0,tP:0,tR:0,tM:0,cY:0,cP:0,cR:0,cM:0,keys:{}}; -var A={head:null,neck:null,jaw:null,headI:null,neckI:null,jawI:null,morphMesh:null,morphIdx:-1}; +var S={tY:0,tP:0,tR:0,tM:0,cY:0,cP:0,cR:0,cM:0,keys:{},phoneme:'neutral',gyroEnabled:false}; +var A={head:null,neck:null,jaw:null,headI:null,neckI:null,jawI:null,morphMesh:null,morphIdx:-1,phonemeMorphs:{}}; var loadedModel=null, vrmData=null, allBones=[]; var orbitTarget=new THREE.Vector3(0,0.3,0),orbitTheta=0,orbitPhi=0.15,orbitDist=3.5,isDrag=false,lastM={x:0,y:0}; +var mobileJoystick={active:false,startX:0,startY:0,currentX:0,currentY:0}; function $(id){return document.getElementById(id)} function showErr(m){$('err-box').textContent=m;$('err-box').style.display='block';$('ok-box').style.display='none'} @@ -534,7 +731,7 @@ function loadFBX(url,name){ function prepareScene(obj,fileName){ if(loadedModel) scene.remove(loadedModel); A.head=A.neck=A.jaw=null;A.headI=A.neckI=A.jawI=null; - A.morphMesh=null;A.morphIdx=-1;allBones=[];vrmData=null; + A.morphMesh=null;A.morphIdx=-1;A.phonemeMorphs={};allBones=[];vrmData=null; loadedModel=obj; @@ -634,6 +831,30 @@ function prepareScene(obj,fileName){ var b=activeRow.querySelector('.morph-map');if(b){b.classList.add('mapped');b.textContent='✓ Mapped'} } } + + // Auto-detect phoneme morphs (A, E, I, O, U) + var phonemePatterns={ + a: [/\baa?\b/i, /viseme.*aa/i, /mouth.*a$/i], + e: [/\bee?\b/i, /viseme.*ee/i, /mouth.*e$/i], + i: [/\bii?\b/i, /viseme.*ii/i, /mouth.*i$/i], + o: [/\boo?\b/i, /viseme.*oh/i, /mouth.*o$/i], + u: [/\buu?\b/i, /viseme.*uu/i, /mouth.*u$/i] + }; + for(var ph in phonemePatterns){ + for(var i=0;i0){ + $('phoneme-toggle').style.display='block'; + console.log('[Phoneme] Auto-detected:',Object.keys(A.phonemeMorphs)); + } } else { $('morph-section').style.display='none'; $('morph-tester').style.display='none'; @@ -1057,6 +1278,12 @@ function applyToModel(){ if(A.morphMesh&&A.morphIdx>=0){ A.morphMesh.morphTargetInfluences[A.morphIdx]=S.cM*CFG.mRange; } + + // Apply phoneme morphs + if(S.phoneme!=='neutral'&&A.phonemeMorphs[S.phoneme]){ + var pm=A.phonemeMorphs[S.phoneme]; + pm.mesh.morphTargetInfluences[pm.idx]=0.8; + } } function updateHUD(){ @@ -1178,6 +1405,228 @@ $('kid-test').onclick=function(){ }; console.log('[HC] Initialized. Three.js r'+THREE.REVISION); + +// ═══════════════════════════════════════════════════════ +// QUICK START TUTORIAL +// ═══════════════════════════════════════════════════════ +(function(){ + var steps=[ + {title:'Welcome!',text:'This tool lets you control a 3D avatar to bypass Discord age verification',step:'Step 1: Load a model using the panel on the right →'}, + {title:'Control Your Avatar',text:'Use WASD for head movement, Space for mouth opening',step:'Step 2: Adjust sensitivity and test controls'}, + {title:'Ready to Go!',text:'When ready, use OBS Virtual Camera to capture this window',step:'Step 3: Open Discord and start verification'} + ]; + var current=0; + var overlay=$('tutorial-overlay'); + var hasSeenTutorial=localStorage.getItem('tutorial_seen'); + + function showStep(i){ + current=i; + $('tut-title').textContent=steps[i].title; + $('tut-text').textContent=steps[i].text; + $('tut-step').textContent=steps[i].step; + $('tut-btn').textContent=i===steps.length-1?'Got it!':'Next'; + var prog=$('tut-progress'); + prog.innerHTML=''; + for(var j=0;jmaxDist){dx=dx/dist*maxDist;dy=dy/dist*maxDist} + joyStick.style.transform='translate(calc(-50% + '+dx+'px), calc(-50% + '+dy+'px))'; + // Map to head rotation + S.tY=(dx/maxDist)*CFG.yawMax; + S.tP=(dy/maxDist)*CFG.pitchMax; + } + function endJoy(){ + mobileJoystick.active=false; + joyStick.style.transform='translate(-50%,-50%)'; + S.tY=0;S.tP=0; + } + + joyHead.addEventListener('touchstart',startJoy); + joyHead.addEventListener('mousedown',startJoy); + document.addEventListener('touchmove',moveJoy); + document.addEventListener('mousemove',moveJoy); + document.addEventListener('touchend',endJoy); + document.addEventListener('mouseup',endJoy); + + // Mobile buttons + $('mobile-mouth').addEventListener('touchstart',function(){this.classList.add('active');S.tM=1}); + $('mobile-mouth').addEventListener('touchend',function(){this.classList.remove('active');S.tM=0}); + $('mobile-roll-l').addEventListener('touchstart',function(){this.classList.add('active');S.tR=-CFG.rollMax}); + $('mobile-roll-l').addEventListener('touchend',function(){this.classList.remove('active');S.tR=0}); + $('mobile-roll-r').addEventListener('touchstart',function(){this.classList.add('active');S.tR=CFG.rollMax}); + $('mobile-roll-r').addEventListener('touchend',function(){this.classList.remove('active');S.tR=0}); +})(); + +// ═══════════════════════════════════════════════════════ +// GYROSCOPE SUPPORT +// ═══════════════════════════════════════════════════════ +if(window.DeviceOrientationEvent){ + window.addEventListener('deviceorientation',function(e){ + if(!S.gyroEnabled)return; + if(e.beta!==null&&e.gamma!==null){ + // Beta: front-back tilt (-180 to 180), Gamma: left-right tilt (-90 to 90) + S.tP=THREE.MathUtils.clamp((e.beta-90)/90*CFG.pitchMax,-CFG.pitchMax,CFG.pitchMax); + S.tY=THREE.MathUtils.clamp(e.gamma/90*CFG.yawMax,-CFG.yawMax,CFG.yawMax); + } + }); + // Auto-enable gyro on mobile + if(/Android|iPhone|iPad/i.test(navigator.userAgent)){ + setTimeout(function(){ + if(typeof DeviceOrientationEvent.requestPermission==='function'){ + DeviceOrientationEvent.requestPermission().then(function(state){ + if(state==='granted'){S.gyroEnabled=true;console.log('[Gyro] Enabled')} + }); + } else { + S.gyroEnabled=true;console.log('[Gyro] Enabled (no permission needed)'); + } + },2000); + } +} + +// ═══════════════════════════════════════════════════════ +// TOUCH GESTURES - Pinch Zoom & Two-Finger Rotate +// ═══════════════════════════════════════════════════════ +(function(){ + var lastDist=0,lastAngle=0; + ren.domElement.addEventListener('touchstart',function(e){ + if(e.touches.length===2){ + var dx=e.touches[1].clientX-e.touches[0].clientX; + var dy=e.touches[1].clientY-e.touches[0].clientY; + lastDist=Math.sqrt(dx*dx+dy*dy); + lastAngle=Math.atan2(dy,dx); + e.preventDefault(); + } + }); + ren.domElement.addEventListener('touchmove',function(e){ + if(e.touches.length===2){ + var dx=e.touches[1].clientX-e.touches[0].clientX; + var dy=e.touches[1].clientY-e.touches[0].clientY; + var dist=Math.sqrt(dx*dx+dy*dy); + var angle=Math.atan2(dy,dx); + // Pinch zoom + if(lastDist>0){ + var scale=dist/lastDist; + orbitDist=Math.max(0.3,Math.min(15,orbitDist/scale)); + } + // Two-finger rotate + if(lastAngle!==0){ + var deltaAngle=angle-lastAngle; + orbitTheta-=deltaAngle; + } + lastDist=dist; + lastAngle=angle; + e.preventDefault(); + } + }); + ren.domElement.addEventListener('touchend',function(){lastDist=0;lastAngle=0}); +})(); + +// ═══════════════════════════════════════════════════════ +// SKELETON LOADING CONTROLLER +// ═══════════════════════════════════════════════════════ +(function(){ + var overlay = $('skeleton-overlay'); + var loadSteps = { + dom: false, + three: false, + loaders: false + }; + + function checkComplete(){ + if(Object.values(loadSteps).every(Boolean)){ + overlay.classList.add('fade-out'); + setTimeout(function(){overlay.remove()}, 400); + } + } + + // Step 1: DOM ready (instant) + loadSteps.dom = true; + + // Step 2: Three.js loaded (instant) + if(typeof THREE !== 'undefined'){ + loadSteps.three = true; + } + + // Step 3: All loaders ready - langsung hide setelah ready + var loaderCheckInterval = setInterval(function(){ + if(loadersReady.gltf && loadersReady.fbx && loadersReady.vrm && window.JSZip){ + loadSteps.loaders = true; + clearInterval(loaderCheckInterval); + checkComplete(); + } + }, 50); + + // Fallback: force hide setelah 5 detik jika ada masalah + setTimeout(function(){ + if(overlay && overlay.parentNode){ + console.warn('[Skeleton] Force hide after 5s'); + overlay.classList.add('fade-out'); + setTimeout(function(){if(overlay.parentNode) overlay.remove()}, 400); + } + }, 5000); +})();