<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Grand Expansive Auth - Validation</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
:root {
--bg-dark: #020202;
--glass-bg: rgba(18, 18, 18, 0.7);
--accent-blue: #3897f0;
--accent-green: #34d399;
--accent-red: #ff4b4b;
--border-light: rgba(255, 255, 255, 0.08);
--text-main: #ffffff;
--text-dim: #a1a1aa;
}
body, html {
margin: 0; padding: 0;
width: 100%; height: 100%;
background-color: var(--bg-dark);
font-family: 'Inter', -apple-system, sans-serif;
display: flex; justify-content: center; align-items: center;
overflow: hidden;
perspective: 1200px;
}
#bg-canvas { position: fixed; top: 0; left: 0; z-index: 0; }
.auth-card {
position: relative; z-index: 10;
width: 380px;
background: var(--glass-bg);
backdrop-filter: blur(60px);
-webkit-backdrop-filter: blur(60px);
border: 1px solid var(--border-light);
border-radius: 40px;
padding: 50px;
box-shadow: 0 60px 120px rgba(0,0,0,1);
text-align: center;
transition: transform 0.15s ease-out;
transform-style: preserve-3d;
will-change: transform;
}
/* Error Shake Animation */
@keyframes shake {
0%, 100% { transform: translateX(0); }
20%, 60% { transform: translateX(-10px); }
40%, 80% { transform: translateX(10px); }
}
.card-error { animation: shake 0.4s cubic-bezier(.36,.07,.19,.97) both; }
h2 { margin: 0 0 8px 0; font-size: 32px; font-weight: 700; color: #fff; letter-spacing: -1px; }
p.subtitle { color: var(--text-dim); font-size: 15px; margin-bottom: 40px; }
.form-container { position: relative; min-height: 260px; }
.auth-form {
position: absolute; width: 100%; top: 0; left: 0;
transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1);
opacity: 0; pointer-events: none; transform: translateY(30px);
}
.auth-form.active { opacity: 1; pointer-events: all; transform: translateY(0); }
.input-group { margin-bottom: 22px; text-align: left; }
label { display: block; font-size: 11px; color: var(--text-dim); margin-bottom: 8px; letter-spacing: 1.2px; text-transform: uppercase; font-weight: 700; }
input {
width: 100%; padding: 16px; background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 16px;
color: white; font-size: 16px; box-sizing: border-box; outline: none; transition: 0.3s;
}
input:focus { border-color: var(--accent-blue); background: rgba(255, 255, 255, 0.07); }
input.error { border-color: var(--accent-red); }
.btn-primary {
width: 100%; padding: 18px; margin-top: 10px;
background: var(--accent-blue); color: white; border: none; border-radius: 16px;
font-size: 16px; font-weight: 600; cursor: pointer; transition: 0.4s;
display: flex; justify-content: center; align-items: center;
}
.btn-primary.loading { background: var(--accent-green); pointer-events: none; }
.btn-primary.loading-error { background: var(--accent-red); pointer-events: none; }
.btn-primary.loading::after, .btn-primary.loading-error::after {
content: ""; width: 22px; height: 22px;
border: 3px solid rgba(255,255,255,0.2);
border-top-color: #fff; border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.footer-link { margin-top: 35px; font-size: 14px; color: var(--text-dim); }
.footer-link span { color: var(--accent-blue); cursor: pointer; font-weight: 600; }
</style>
</head>
<body>
<canvas id="bg-canvas"></canvas>
<div class="auth-card" id="card">
<h2 id="title">Welcome back</h2>
<p class="subtitle" id="subtitle">Connect to your secure dashboard.</p>
<div class="form-container">
<div class="auth-form active" id="loginForm">
<div class="input-group">
<label>Account Email</label>
<input type="email" id="loginEmail" placeholder="you@example.com">
</div>
<div class="input-group">
<label>Security Key</label>
<input type="password" id="loginPass" placeholder="••••••••">
</div>
<button class="btn-primary" onclick="validateAndSubmit('loginForm')">
<span class="btn-text">Authenticate</span>
</button>
</div>
<div class="auth-form" id="signupForm">
<div class="input-group">
<label>Full Name</label>
<input type="text" id="regName" placeholder="Alex Morgan">
</div>
<div class="input-group">
<label>Account Email</label>
<input type="email" id="regEmail" placeholder="you@example.com">
</div>
<div class="input-group">
<label>Security Key</label>
<input type="password" id="regPass" placeholder="••••••••">
</div>
<button class="btn-primary" onclick="validateAndSubmit('signupForm')">
<span class="btn-text">Get Started</span>
</button>
</div>
</div>
<div class="footer-link" id="toggleText">
New here? <span onclick="toggleAuth(true)">Create account</span>
</div>
</div>
<script>
const canvas = document.getElementById('bg-canvas');
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: true });
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 2000);
camera.position.z = 22;
const particlesCount = 18000;
const positions = new Float32Array(particlesCount * 3);
const randomOffsets = new Float32Array(particlesCount);
for (let i = 0; i < particlesCount; i++) {
const ringIndex = Math.floor(i / 1200) + 1;
const radius = ringIndex * 5.5;
const angle = (i % 1200) / 1200 * Math.PI * 2;
positions[i * 3] = Math.cos(angle) * radius;
positions[i * 3 + 1] = Math.sin(angle) * radius;
positions[i * 3 + 2] = (Math.random() - 0.5) * 3.0;
randomOffsets[i] = Math.random();
}
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.setAttribute('randomOffset', new THREE.BufferAttribute(randomOffsets, 1));
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0 },
uWaveActive: { value: 0.0 },
uIsError: { value: 0.0 }
},
vertexShader: `
uniform float uTime;
uniform float uWaveActive;
attribute float randomOffset;
varying float vColorMix;
varying float vOpacity;
void main() {
vec3 pos = position;
float dist = length(pos.xy);
pos.xy += sin(uTime * 0.1 + randomOffset * 6.28) * 0.12;
float wave = 0.0;
if (uWaveActive > 0.5) {
float pulse = sin(dist * 0.15 - uTime * 5.0);
wave = smoothstep(0.3, 1.0, pulse);
}
vColorMix = wave;
vec4 mvPos = modelViewMatrix * vec4(pos, 1.0);
gl_PointSize = (2.2 + vColorMix * 5.5) * (15.0 / -mvPos.z);
gl_Position = projectionMatrix * mvPos;
vOpacity = smoothstep(90.0, 5.0, dist);
}
`,
fragmentShader: `
uniform float uIsError;
varying float vColorMix;
varying float vOpacity;
void main() {
if (distance(gl_PointCoord, vec2(0.5)) > 0.5) discard;
vec3 blueCol = vec3(0.3, 0.4, 0.55);
vec3 successCol = vec3(0.2, 1.0, 0.45);
vec3 errorCol = vec3(1.0, 0.2, 0.2);
vec3 activeCol = mix(successCol, errorCol, uIsError);
vec3 color = mix(blueCol, activeCol, vColorMix);
gl_FragColor = vec4(color, vOpacity * 0.5);
}
`,
transparent: true, blending: THREE.AdditiveBlending
});
const points = new THREE.Points(geometry, material);
scene.add(points);
function resize() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
window.addEventListener('resize', resize);
resize();
// VALIDATION LOGIC
function validateAndSubmit(formId) {
const form = document.getElementById(formId);
const inputs = form.querySelectorAll('input');
const btn = form.querySelector('.btn-primary');
const card = document.getElementById('card');
let isValid = true;
inputs.forEach(input => {
if (!input.value.trim()) {
isValid = false;
input.classList.add('error');
} else {
input.classList.remove('error');
}
});
if (!isValid) {
// RED WAVE & SHAKE
material.uniforms.uIsError.value = 1.0;
material.uniforms.uWaveActive.value = 1.0;
btn.classList.add('loading-error');
card.classList.add('card-error');
setTimeout(() => {
material.uniforms.uWaveActive.value = 0.0;
btn.classList.remove('loading-error');
card.classList.remove('card-error');
}, 3000);
} else {
// GREEN WAVE
material.uniforms.uIsError.value = 0.0;
material.uniforms.uWaveActive.value = 1.0;
btn.classList.add('loading');
setTimeout(() => {
material.uniforms.uWaveActive.value = 0.0;
btn.classList.remove('loading');
alert("Authenticated Successfully!");
}, 3000);
}
}
function toggleAuth(isSignup) {
const loginForm = document.getElementById('loginForm');
const signupForm = document.getElementById('signupForm');
const title = document.getElementById('title');
const toggleText = document.getElementById('toggleText');
if (isSignup) {
loginForm.classList.remove('active');
setTimeout(() => signupForm.classList.add('active'), 100);
title.innerText = "Create Account";
toggleText.innerHTML = `Member? <span onclick="toggleAuth(false)">Sign in</span>`;
} else {
signupForm.classList.remove('active');
setTimeout(() => loginForm.classList.add('active'), 100);
title.innerText = "Welcome back";
toggleText.innerHTML = `New here? <span onclick="toggleAuth(true)">Create account</span>`;
}
}
function animate(time) {
material.uniforms.uTime.value = time * 0.001;
points.rotation.z += 0.00008;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
document.addEventListener('mousemove', (e) => {
const mX = (e.clientX / window.innerWidth) * 2 - 1;
const mY = -(e.clientY / window.innerHeight) * 2 + 1;
document.getElementById('card').style.transform = `rotateX(${mY * 10}deg) rotateY(${mX * 10}deg)`;
});
</script>
</body>
</html>“Create a "Grand Expansive Auth - Validation" component. Use Three.js for 3D WebGL rendering. Implement custom GLSL shaders for visual effects. Apply keyframe animations, glass-morphism / backdrop blur, 3D CSS perspective, layered shadows. Color palette: #020202, #3897f0, #34d399, #ff4b4b, #ffffff, #a1a1aa. Layout: Flexbox, full-screen fixed canvas background. Interactivity: mouse tracking, click interactions, continuous animation loop, responsive resize handling. Includes form input fields. Render a particle system effect.”