Close Menu

    Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    What's Hot

    How to make Interactive Login Form Lamp using HTML CSS JS

    19 October 2026

    How to make 3D Globe with Location Pointer using HTML CSS and JavaScript

    15 October 2026

    How to create Valentine’s Love Button Animation using HTML CSS and JS

    13 October 2026
    Facebook X (Twitter) Instagram YouTube Telegram Threads
    Coding StellaCoding Stella
    • Home
    • Blog
    • HTML & CSS
      • Login Form
    • JavaScript
    • Hire us!
    Coding StellaCoding Stella
    Home » How to make Interactive Login Form Lamp using HTML CSS JS
    HTML & CSS

    How to make Interactive Login Form Lamp using HTML CSS JS

    Coding StellaBy Coding Stella19 October 2026No Comments29 Mins Read
    Share Facebook Twitter Pinterest LinkedIn Tumblr Reddit Email WhatsApp Copy Link

    Let’s create a stunning Interactive Lamp Login Animation using HTML, CSS, and JavaScript! đŸ’¡ In this project, we’ll build a modern login page featuring a realistic animated desk lamp that users can turn on or off by pulling its cord. When the lamp switches on, a beautiful glassmorphism login form smoothly appears with glowing effects, floating particles, and elegant animations. Users can also customize the lamp’s lighting with five different colors, making the experience even more interactive and visually appealing.

    We’ll use:

    • HTML: To build the page structure, including a detailed SVG lamp, interactive pull cord, color selection buttons, sound controls, and a login form with Sign In and Sign Up options.
    • CSS: To create a modern dark-themed interface with realistic lighting, colorful glow effects, glassmorphism styling, animated light beams, smooth transitions, responsive layouts, and beautiful hover effects.
    • JavaScript: To bring everything to life using GSAP and Draggable, allowing users to pull the lamp cord, switch between five lighting colors, toggle realistic sound effects, animate floating dust particles, control password visibility, switch between login and registration forms, and display an animated login success message.

    This project is perfect for learning SVG animations, GSAP, Draggable interactions, JavaScript event handling, DOM manipulation, CSS animations, glassmorphism, Canvas particle effects, Web Audio API, responsive design, and interactive UI development. It’s a creative way to combine animations, user interactions, and modern web design to build a unique login experience using HTML, CSS, and JavaScript!

    HTML :

    Creates the structure of the interactive lamp login page, including the SVG lamp, pull string, color buttons, sound toggle, login form, password field, social login icons, and success message.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Interactive Lamp Login | @coding.stella</title>
      <link rel="preconnect" href="https://fonts.googleapis.com">
      <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
      <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap"
        rel="stylesheet">
      <link rel="stylesheet" href="style.css">
    </head>
    
    <body data-on="false">
    
      <div class="ambient-glow"></div>
      <canvas id="dustCanvas"></canvas>
    
      <!-- Controls -->
      <div class="quick-controls">
        <div class="color-palette" id="colorPalette" title="Choose Lamp Color">
          <button class="color-dot-btn active" data-color="amber" style="--dot-color: #ffab3d;" aria-label="Amber Light"
            title="Amber (Warm)"></button>
          <button class="color-dot-btn" data-color="cyan" style="--dot-color: #00f0ff;" aria-label="Cyan Light"
            title="Cyan (Cyber)"></button>
          <button class="color-dot-btn" data-color="rose" style="--dot-color: #ff3385;" aria-label="Rose Light"
            title="Rose (Sunset)"></button>
          <button class="color-dot-btn" data-color="mint" style="--dot-color: #00e676;" aria-label="Mint Light"
            title="Mint (Emerald)"></button>
          <button class="color-dot-btn" data-color="moonlight" style="--dot-color: #d8e5ff;" aria-label="Moonlight"
            title="Moonlight (Cool White)"></button>
        </div>
    
        <button class="sound-toggle" id="soundToggle" title="Toggle Sound" aria-label="Toggle Sound">
          <svg class="sound-icon sound-on" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
            <path d="M15.54 8.46a5 5 0 0 1 0 7.07"></path>
            <path d="M19.07 4.93a10 10 0 0 1 0 14.14"></path>
          </svg>
          <svg class="sound-icon sound-off hidden" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
            <line x1="23" y1="9" x2="17" y2="15"></line>
            <line x1="17" y1="9" x2="23" y2="15"></line>
          </svg>
        </button>
      </div>
    
      <main class="scene-container">
    
        <!-- Lamp -->
        <div class="lamp-stage">
          <div class="lamp-wrapper">
    
            <svg class="lamp-svg" viewBox="0 0 400 500" xmlns="http://www.w3.org/2000/svg">
              <defs>
                <linearGradient id="metalArm" x1="0" y1="0" x2="1" y2="0">
                  <stop offset="0%" stop-color="#3e434a" />
                  <stop offset="50%" stop-color="#7a828e" />
                  <stop offset="100%" stop-color="#24272c" />
                </linearGradient>
    
                <linearGradient id="brassJoint" x1="0" y1="0" x2="1" y2="1">
                  <stop offset="0%" stop-color="#ffe299" />
                  <stop offset="45%" stop-color="#c99738" />
                  <stop offset="85%" stop-color="#805915" />
                  <stop offset="100%" stop-color="#f5d38a" />
                </linearGradient>
    
                <linearGradient id="shadeExterior" x1="0" y1="0" x2="1" y2="1">
                  <stop offset="0%" stop-color="#343840" />
                  <stop offset="40%" stop-color="#21252a" />
                  <stop offset="100%" stop-color="#121417" />
                </linearGradient>
    
                <linearGradient id="shadeHighlight" x1="0" y1="0" x2="1" y2="0">
                  <stop offset="0%" stop-color="#ffffff" stop-opacity="0" />
                  <stop offset="42%" stop-color="#ffffff" stop-opacity="0.16" />
                  <stop offset="72%" stop-color="#ffffff" stop-opacity="0.025" />
                  <stop offset="100%" stop-color="#ffffff" stop-opacity="0" />
                </linearGradient>
    
                <linearGradient id="shadeRim" x1="0" y1="0" x2="1" y2="0">
                  <stop offset="0%" stop-color="#ffd584" />
                  <stop offset="50%" stop-color="#e2ab46" />
                  <stop offset="100%" stop-color="#996a1a" />
                </linearGradient>
    
                <radialGradient id="reflectorOff" cx="50%" cy="40%" r="70%">
                  <stop offset="0%" stop-color="#2c3036" />
                  <stop offset="55%" stop-color="#1a1d22" />
                  <stop offset="100%" stop-color="#0e1012" />
                </radialGradient>
    
                <radialGradient id="reflectorOn" cx="50%" cy="40%" r="70%">
                  <stop offset="0%" stop-color="#ffffff" stop-opacity="0.95" />
                  <stop offset="35%" stop-color="var(--lamp-glow, #ffe194)" stop-opacity="0.85" />
                  <stop offset="70%" stop-color="var(--lamp-accent, #ffab3d)" stop-opacity="0.6" />
                  <stop offset="100%" stop-color="#2a2015" stop-opacity="0.85" />
                </radialGradient>
    
                <linearGradient id="volumetricBeam" x1="0%" y1="0%" x2="90%" y2="70%">
                  <stop offset="0%" stop-color="var(--beam-start, rgba(255, 220, 130, 0.45))" />
                  <stop offset="25%" stop-color="var(--beam-mid, rgba(255, 195, 90, 0.22))" />
                  <stop offset="65%" stop-color="var(--beam-far, rgba(255, 175, 60, 0.08))" />
                  <stop offset="100%" stop-color="rgba(0, 0, 0, 0)" />
                </linearGradient>
    
                <filter id="bulbGlowFilter" x="-60%" y="-60%" width="220%" height="220%">
                  <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="blur1" />
                  <feGaussianBlur in="SourceGraphic" stdDeviation="14" result="blur2" />
                  <feMerge>
                    <feMergeNode in="blur2" />
                    <feMergeNode in="blur1" />
                    <feMergeNode in="SourceGraphic" />
                  </feMerge>
                </filter>
    
                <filter id="beamSoftFilter" x="-10%" y="-10%" width="120%" height="120%">
                  <feGaussianBlur stdDeviation="8" />
                </filter>
              </defs>
    
              <ellipse class="desk-shadow" cx="190" cy="460" rx="90" ry="16" fill="rgba(0, 0, 0, 0.55)" />
    
              <g class="light-beam-group">
                <polygon class="svg-light-beam" points="182,185 308,225 820,480 340,510" fill="url(#volumetricBeam)"
                  filter="url(#beamSoftFilter)" />
              </g>
    
              <g class="lamp-base-group">
                <ellipse cx="190" cy="445" rx="72" ry="14" fill="#15171a" />
                <ellipse cx="190" cy="443" rx="70" ry="12" fill="url(#metalArm)" />
                <ellipse cx="190" cy="441" rx="66" ry="10" fill="#1c1f24" />
                <ellipse cx="190" cy="439" rx="60" ry="7" fill="none" stroke="#8e949f" stroke-opacity=".22"
                  stroke-width=".8" />
                <circle cx="190" cy="439" r="15" fill="url(#brassJoint)" />
                <circle cx="190" cy="439" r="7" fill="#15171a" />
                <circle cx="190" cy="439" r="3.2" fill="#747b86" />
              </g>
    
              <g class="lamp-arm-lower">
                <line x1="186" y1="439" x2="156" y2="295" stroke="url(#metalArm)" stroke-width="4.5"
                  stroke-linecap="round" />
                <line x1="194" y1="439" x2="164" y2="295" stroke="url(#metalArm)" stroke-width="4.5"
                  stroke-linecap="round" />
                <path d="M 188 420 Q 175 360 163 305" stroke="#606670" stroke-width="2" stroke-dasharray="3,3" fill="none"
                  opacity="0.6" />
              </g>
    
              <g class="lamp-elbow-joint">
                <circle cx="160" cy="295" r="13" fill="url(#brassJoint)" />
                <circle cx="160" cy="295" r="6" fill="#1c1f24" />
                <circle cx="160" cy="295" r="3.3" fill="#858b94" />
                <line x1="155" y1="295" x2="165" y2="295" stroke="url(#brassJoint)" stroke-width="2" />
              </g>
    
              <g class="lamp-arm-upper">
                <line x1="160" y1="295" x2="215" y2="175" stroke="url(#metalArm)" stroke-width="5" stroke-linecap="round" />
                <path d="M 190 439 Q 168 360 160 295 Q 190 230 215 175" stroke="#101114" stroke-width="3" fill="none"
                  stroke-linecap="round" />
              </g>
    
              <g class="lamp-neck">
                <circle cx="215" cy="175" r="11" fill="url(#brassJoint)" />
                <rect x="209" y="162" width="16" height="15" rx="3" fill="url(#metalArm)"
                  transform="rotate(25, 217, 169)" />
              </g>
    
              <g class="lamp-shade-assembly" id="shadeAssembly">
                <path class="lamp-shade-body"
                  d="M 182.3 184.6 C 188 135, 220 112, 248 115 C 275 118, 298 155, 307.7 225.4 A 66 22 18 0 1 182.3 184.6 Z"
                  fill="url(#shadeExterior)" stroke="#16181b" stroke-width="1.8" />
    
                <path class="shade-enamel-highlight"
                  d="M 187 181 C 193 139, 221 119, 247 120 C 267 122, 286 144, 297 178 C 271 163, 224 153, 187 181 Z"
                  fill="url(#shadeHighlight)" />
                <path d="M 204 148 C 216 125, 235 119, 251 122" fill="none" stroke="#aeb5c2" stroke-opacity=".17"
                  stroke-width="1.2" stroke-linecap="round" />
    
                <ellipse class="shade-reflector-off" cx="245" cy="205" rx="66" ry="22" transform="rotate(18, 245, 205)"
                  fill="url(#reflectorOff)" />
    
                <ellipse class="shade-reflector-on" cx="245" cy="205" rx="66" ry="22" transform="rotate(18, 245, 205)"
                  fill="url(#reflectorOn)" />
    
                <ellipse class="reflector-detail" cx="245" cy="205" rx="49" ry="14" transform="rotate(18, 245, 205)"
                  fill="none" stroke="#fff3ce" stroke-opacity=".16" stroke-width=".8" />
    
                <ellipse cx="245" cy="205" rx="66" ry="22" transform="rotate(18, 245, 205)" fill="none"
                  stroke="rgba(255, 213, 132, 0.25)" stroke-width="1" />
    
                <path class="shade-rim-trim" d="M 182.3 184.6 A 66 22 18 0 0 307.7 225.4" stroke="url(#shadeRim)"
                  stroke-width="4" fill="none" stroke-linecap="round" />
    
                <g class="bulb-unit" id="bulbUnit">
                  <ellipse class="bulb-glass" cx="245" cy="195" rx="14" ry="17" transform="rotate(18, 245, 195)"
                    fill="rgba(255, 255, 255, 0.08)" stroke="rgba(255, 255, 255, 0.25)" stroke-width="1" />
                  <path d="M 239 190 Q 242 181 247 183" fill="none" stroke="#fff" stroke-opacity=".55" stroke-width="1.2"
                    stroke-linecap="round" />
                  <path class="bulb-filament" d="M 241 189 Q 245 183 249 189" stroke="#555" stroke-width="1.8"
                    fill="none" />
                  <circle class="bulb-glow-core" cx="245" cy="188" r="11" fill="var(--lamp-glow, #ffe194)"
                    filter="url(#bulbGlowFilter)" opacity="0" />
                </g>
    
                <g class="cord-socket-grommet">
                  <rect x="242" y="206" width="6" height="6" rx="1.5" fill="url(#brassJoint)" stroke="#68420e"
                    stroke-width="0.8" />
                  <circle cx="245" cy="212" r="3" fill="#ffe299" stroke="#7a5513" stroke-width="0.8" />
                  <circle cx="245" cy="212" r="1.3" fill="#181105" />
                </g>
              </g>
    
              <!-- Pull String System -->
              <g class="pull-cord-system">
                <path class="elastic-cord-path" id="elasticCord" d="M 245 212 L 245 300" stroke="#e8bb54" stroke-width="2.6"
                  stroke-linecap="round" />
    
                <g class="cord-bead-group" id="cordBead" cursor="grab">
                  <circle class="bead-aura" cx="0" cy="0" r="16" fill="var(--lamp-accent)" opacity="0" />
                  <path class="bead-shape" d="M -4 -8 L 4 -8 L 7 6 C 7 10, -7 10, -7 6 Z" fill="url(#brassJoint)"
                    stroke="#7a5513" stroke-width="0.8" />
                  <ellipse cx="2" cy="0" rx="2" ry="4" fill="#fff" opacity="0.5" />
                  <circle class="cord-hit-area" id="cordHit" cx="0" cy="0" r="32" fill="transparent" />
                </g>
              </g>
    
            </svg>
    
            <div class="cord-tooltip" id="cordTooltip">
              <span>Pull string to turn on</span>
              <div class="tooltip-arrow"></div>
            </div>
    
          </div>
        </div>
    
        <!-- Login Form -->
        <div class="form-stage">
          <div class="login-card" id="loginCard">
    
            <div class="card-header">
              <h1 class="card-title">Welcome</h1>
              <p class="card-subtitle">Sign in to continue to your account</p>
            </div>
    
            <div class="auth-tabs" data-active="signin">
              <button class="auth-tab active" data-tab="signin" id="tabSignIn">Sign In</button>
              <button class="auth-tab" data-tab="register" id="tabRegister">Sign Up</button>
              <div class="tab-slider" id="tabSlider"></div>
            </div>
    
            <form class="auth-form" id="authForm" autocomplete="off" onsubmit="return false;">
    
              <div class="form-group">
                <label for="userField">Username or Email</label>
                <div class="input-wrapper">
                  <svg class="field-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                    <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
                    <circle cx="12" cy="7" r="4"></circle>
                  </svg>
                  <input type="text" id="userField" placeholder="Enter username or email" required />
                </div>
              </div>
    
              <div class="form-group">
                <div class="label-row">
                  <label for="passField">Password</label>
                  <a href="#" class="forgot-link" id="forgotLink">Forgot?</a>
                </div>
                <div class="input-wrapper">
                  <svg class="field-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                    <rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
                    <path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
                  </svg>
                  <input type="password" id="passField" placeholder="Enter password" required />
                  <button type="button" class="eye-toggle" id="eyeToggle" aria-label="Toggle password visibility">
                    <svg class="eye-icon eye-show" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                      <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
                      <circle cx="12" cy="12" r="3"></circle>
                    </svg>
                    <svg class="eye-icon eye-hide hidden" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                      stroke-width="2">
                      <path
                        d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24">
                      </path>
                      <line x1="1" y1="1" x2="23" y2="23"></line>
                    </svg>
                  </button>
                </div>
              </div>
    
              <div class="options-row">
                <label class="custom-checkbox">
                  <input type="checkbox" id="rememberMe" checked />
                  <span class="checkbox-box">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
                      <polyline points="20 6 9 17 4 12"></polyline>
                    </svg>
                  </span>
                  <span class="checkbox-label">Remember me</span>
                </label>
              </div>
    
              <button type="submit" class="submit-btn" id="submitBtn">
                <span class="btn-glow-layer"></span>
                <span class="btn-content">
                  <span class="btn-text">Sign In</span>
                  <svg class="btn-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
                    <line x1="5" y1="12" x2="19" y2="12"></line>
                    <polyline points="12 5 19 12 12 19"></polyline>
                  </svg>
                </span>
                <div class="btn-spinner hidden" id="btnSpinner"></div>
                <div class="btn-success-icon hidden" id="btnSuccess">
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
                    <polyline points="20 6 9 17 4 12"></polyline>
                  </svg>
                </div>
              </button>
    
              <div class="auth-divider">
                <span class="divider-line"></span>
                <span class="divider-text">or continue with</span>
                <span class="divider-line"></span>
              </div>
    
              <div class="social-row">
                <button type="button" class="social-btn" title="Sign in with Google" aria-label="Sign in with Google">
                  <svg viewBox="0 0 24 24">
                    <path fill="#EA4335"
                      d="M12 5c1.6 0 3 .6 4.1 1.7l3.1-3.1C17.3 1.8 14.8 1 12 1 7.4 1 3.5 3.6 1.6 7.4l3.7 2.9C6.2 7.5 8.9 5 12 5z" />
                    <path fill="#4285F4"
                      d="M23.5 12.3c0-.8-.1-1.7-.2-2.3H12v4.5h6.5c-.3 1.5-1.1 2.8-2.4 3.7l3.7 2.9c2.2-2 3.7-5 3.7-8.8z" />
                    <path fill="#FBBC05"
                      d="M5.3 14.7c-.2-.7-.4-1.5-.4-2.7s.1-2 .4-2.7L1.6 6.4C.6 8.3 0 10.1 0 12s.6 3.7 1.6 5.6l3.7-2.9z" />
                    <path fill="#34A853"
                      d="M12 23c3.2 0 6-1.1 8-3l-3.7-2.9c-1.1.7-2.5 1.2-4.3 1.2-3.1 0-5.8-2.5-6.7-5.3L1.6 16c1.9 3.8 5.8 7 10.4 7z" />
                  </svg>
                </button>
                <button type="button" class="social-btn" title="Sign in with GitHub" aria-label="Sign in with GitHub">
                  <svg viewBox="0 0 24 24" fill="currentColor">
                    <path fill-rule="evenodd" clip-rule="evenodd"
                      d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.53 1.032 1.53 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" />
                  </svg>
                </button>
                <button type="button" class="social-btn" title="Sign in with Apple" aria-label="Sign in with Apple">
                  <svg viewBox="0 0 24 24" fill="currentColor">
                    <path
                      d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M15.97 6.89c.63-.78 1.06-1.86.94-2.94-1 .04-2.13.67-2.77 1.45-.58.68-1.08 1.79-.94 2.84 1.12.09 2.14-.57 2.77-1.35z" />
                  </svg>
                </button>
              </div>
    
            </form>
    
            <div class="success-overlay hidden" id="successOverlay">
              <div class="success-box">
                <div class="success-ring">
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
                    <polyline points="20 6 9 17 4 12"></polyline>
                  </svg>
                </div>
                <h3>Signed In Successfully</h3>
                <p>Welcome back! Your workspace is ready.</p>
                <button class="reset-demo-btn" id="resetDemoBtn">Test Again</button>
              </div>
            </div>
    
          </div>
        </div>
    
      </main>
    
      <script src="https://unpkg.com/gsap@3/dist/gsap.min.js"></script>
      <script src="https://unpkg.com/gsap@3/dist/Draggable.min.js"></script>
      <script src="script.js"></script>
    </body>
    
    </html>

    CSS :

    Styles the entire page with a dark theme, colorful lamp effects, glowing light beams, animated buttons, input fields, smooth transitions, different lamp color themes, and responsive layouts for mobile and desktop screens.

    /* Theme Spectrums */
    
    :root,
    [data-color="amber"] {
      --lamp-accent: #ffab3d;
      --lamp-glow: #ffe194;
      --lamp-secondary: #d48b28;
      --beam-color: rgba(255, 185, 75, 0.22);
      --beam-start: rgba(255, 220, 130, 0.45);
      --beam-mid: rgba(255, 195, 90, 0.22);
      --beam-far: rgba(255, 175, 60, 0.08);
      --lamp-focus-glow: rgba(255, 171, 61, 0.18);
    
      --bg-dark: #0c0e12;
      --bg-illuminated: #161920;
      --card-bg: rgba(18, 22, 28, 0.72);
      --card-border: rgba(255, 255, 255, 0.09);
      --input-bg: rgba(255, 255, 255, 0.04);
      --input-border: rgba(255, 255, 255, 0.1);
      --text-primary: #f0f3f8;
      --text-muted: #8b95a5;
      --text-dim: #545c6b;
    }
    
    [data-color="cyan"] {
      --lamp-accent: #00f0ff;
      --lamp-glow: #a6f9ff;
      --lamp-secondary: #009eb0;
      --beam-color: rgba(0, 240, 255, 0.2);
      --beam-start: rgba(160, 245, 255, 0.45);
      --beam-mid: rgba(0, 220, 255, 0.22);
      --beam-far: rgba(0, 180, 220, 0.08);
      --lamp-focus-glow: rgba(0, 240, 255, 0.18);
    }
    
    [data-color="rose"] {
      --lamp-accent: #ff3385;
      --lamp-glow: #ffa3c7;
      --lamp-secondary: #ba1656;
      --beam-color: rgba(255, 51, 133, 0.2);
      --beam-start: rgba(255, 160, 205, 0.45);
      --beam-mid: rgba(255, 70, 150, 0.22);
      --beam-far: rgba(255, 30, 110, 0.08);
      --lamp-focus-glow: rgba(255, 51, 133, 0.18);
    }
    
    [data-color="mint"] {
      --lamp-accent: #00e676;
      --lamp-glow: #b9f6ca;
      --lamp-secondary: #00964b;
      --beam-color: rgba(0, 230, 118, 0.2);
      --beam-start: rgba(180, 255, 215, 0.45);
      --beam-mid: rgba(0, 225, 115, 0.22);
      --beam-far: rgba(0, 170, 85, 0.08);
      --lamp-focus-glow: rgba(0, 230, 118, 0.18);
    }
    
    [data-color="moonlight"] {
      --lamp-accent: #d8e5ff;
      --lamp-glow: #ffffff;
      --lamp-secondary: #7b9cd4;
      --beam-color: rgba(200, 220, 255, 0.22);
      --beam-start: rgba(255, 255, 255, 0.45);
      --beam-mid: rgba(210, 230, 255, 0.22);
      --beam-far: rgba(170, 200, 245, 0.08);
      --lamp-focus-glow: rgba(216, 229, 255, 0.2);
    }
    
    /* Global Reset */
    *,
    *::before,
    *::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    html,
    body {
      width: 100%;
      min-height: 100vh;
      font-family: 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
      background-color: var(--bg-dark);
      color: var(--text-primary);
      overflow-x: hidden;
      position: relative;
      transition: background-color 0.8s ease;
      user-select: none;
    }
    
    body[data-on="true"] {
      background-color: var(--bg-illuminated);
    }
    
    /* Ambient Radial Glow on Room Wall */
    .ambient-glow {
      position: fixed;
      inset: 0;
      background: radial-gradient(circle at 38% 38%, var(--beam-color), transparent 65%);
      opacity: 0;
      pointer-events: none;
      z-index: 1;
      transition: opacity 0.8s ease, background 0.5s ease;
    }
    
    body[data-on="true"] .ambient-glow {
      opacity: 0.85;
    }
    
    /* Dust Particles Canvas */
    #dustCanvas {
      position: fixed;
      inset: 0;
      width: 100%;
      height: 100%;
      pointer-events: none;
      z-index: 2;
    }
    
    /* Minimal Controls in Corner */
    .quick-controls {
      position: fixed;
      top: 24px;
      right: 28px;
      z-index: 50;
      display: flex;
      align-items: center;
      gap: 12px;
    }
    
    /* Minimal Color Palette */
    .color-palette {
      display: flex;
      align-items: center;
      gap: 8px;
      background: rgba(255, 255, 255, 0.05);
      border: 1px solid rgba(255, 255, 255, 0.09);
      padding: 6px 12px;
      border-radius: 30px;
      backdrop-filter: blur(12px);
      -webkit-backdrop-filter: blur(12px);
    }
    
    .color-dot-btn {
      width: 18px;
      height: 18px;
      border-radius: 50%;
      background: var(--dot-color);
      border: 2px solid transparent;
      cursor: pointer;
      transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
      position: relative;
      outline: none;
    }
    
    .color-dot-btn:hover {
      transform: scale(1.22);
      box-shadow: 0 0 10px var(--dot-color);
    }
    
    .color-dot-btn.active {
      transform: scale(1.2);
      border-color: #fff;
      box-shadow: 0 0 12px var(--dot-color);
    }
    
    .sound-toggle {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 42px;
      height: 42px;
      border-radius: 50%;
      background: rgba(255, 255, 255, 0.06);
      border: 1px solid rgba(255, 255, 255, 0.1);
      color: var(--text-muted);
      cursor: pointer;
      transition: all 0.3s ease;
      backdrop-filter: blur(10px);
    }
    
    .sound-toggle:hover {
      background: rgba(255, 255, 255, 0.12);
      color: #fff;
      transform: scale(1.05);
    }
    
    .sound-icon {
      width: 18px;
      height: 18px;
    }
    
    .hidden {
      display: none !important;
    }
    
    /* Scene Layout */
    .scene-container {
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 2rem;
      position: relative;
      z-index: 10;
      max-width: 1160px;
      margin: 0 auto;
      gap: 2rem;
    }
    
    /* Lamp Stage */
    .lamp-stage {
      flex: 1 1 420px;
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
    }
    
    .lamp-wrapper {
      position: relative;
      width: 400px;
      height: 520px;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    .lamp-svg {
      width: 100%;
      height: 100%;
      overflow: visible;
      filter: drop-shadow(0 15px 35px rgba(0, 0, 0, 0.6));
      transition: filter 500ms ease, transform 500ms cubic-bezier(.2, .7, .2, 1);
      transform-origin: 54% 44%;
    }
    
    .lamp-wrapper:hover .lamp-svg {
      filter: drop-shadow(0 18px 38px rgba(0, 0, 0, 0.55));
    }
    
    .lamp-shade-body {
      transition: filter 500ms ease;
    }
    
    body[data-on="true"] .lamp-shade-body {
      filter: drop-shadow(0 0 12px var(--lamp-accent));
    }
    
    .shade-enamel-highlight,
    .reflector-detail {
      pointer-events: none;
    }
    
    .reflector-detail {
      opacity: .7;
      transition: opacity 400ms ease;
    }
    
    body[data-on="true"] .reflector-detail {
      opacity: .95;
    }
    
    /* Volumetric Light Beam (Inside SVG) */
    .svg-light-beam {
      opacity: 0;
      visibility: hidden;
      mix-blend-mode: screen;
      pointer-events: none;
      transition: opacity 0.4s ease, visibility 0.4s ease;
    }
    
    body[data-on="true"] .svg-light-beam {
      opacity: 1;
      visibility: visible;
    }
    
    body[data-on="true"] .svg-light-beam {
      animation: beam-bloom 1.4s ease-out both;
    }
    
    @keyframes beam-bloom {
      from {
        opacity: .15;
      }
    
      to {
        opacity: 1;
      }
    }
    
    /* Shade Reflector States */
    .shade-reflector-off {
      opacity: 1;
    }
    
    .shade-reflector-on {
      opacity: 0;
      transition: opacity 0.35s ease;
    }
    
    body[data-on="true"] .shade-reflector-on {
      opacity: 1;
    }
    
    /* Bulb Glow */
    .bulb-glow-core {
      opacity: 0;
      transition: opacity 0.3s ease;
    }
    
    body[data-on="true"] .bulb-glow-core {
      opacity: 0.95;
      animation: bulb-flicker-in 650ms ease-out both;
    }
    
    @keyframes bulb-flicker-in {
      0% {
        opacity: 0;
      }
    
      22% {
        opacity: .55;
      }
    
      34% {
        opacity: .28;
      }
    
      48% {
        opacity: .9;
      }
    
      62% {
        opacity: .72;
      }
    
      100% {
        opacity: .95;
      }
    }
    
    .bulb-filament {
      stroke: #555;
      transition: stroke 0.3s ease, filter 0.3s ease;
    }
    
    @media (prefers-reduced-motion: reduce) {
    
      .lamp-svg,
      .lamp-shade-body,
      .reflector-detail,
      .svg-light-beam,
      .bulb-glow-core,
      .bead-aura,
      .cord-tooltip {
        animation: none !important;
        transition-duration: .01ms !important;
      }
    }
    
    body[data-on="true"] .bulb-filament {
      stroke: #fff;
      filter: drop-shadow(0 0 6px var(--lamp-accent));
    }
    
    /* Elastic String & Bead Handle */
    .elastic-cord-path {
      transition: stroke 0.3s ease;
    }
    
    body[data-on="true"] .elastic-cord-path {
      stroke: var(--lamp-glow);
      filter: drop-shadow(0 0 4px var(--lamp-accent));
    }
    
    .cord-bead-group {
      cursor: grab;
      touch-action: none;
    }
    
    .cord-bead-group:active {
      cursor: grabbing;
    }
    
    .bead-aura {
      transition: opacity 0.3s ease;
    }
    
    body[data-on="true"] .bead-aura {
      opacity: 0.35;
      animation: pulseAura 2.2s infinite ease-in-out;
    }
    
    @keyframes pulseAura {
    
      0%,
      100% {
        transform: scale(1);
        opacity: 0.25;
      }
    
      50% {
        transform: scale(1.3);
        opacity: 0.5;
      }
    }
    
    /* Pull Tooltip */
    .cord-tooltip {
      position: absolute;
      top: 360px;
      left: 175px;
      background: rgba(16, 19, 25, 0.88);
      border: 1px solid rgba(255, 255, 255, 0.14);
      padding: 6px 14px;
      border-radius: 20px;
      font-size: 0.76rem;
      font-weight: 600;
      color: #fff;
      letter-spacing: 0.02em;
      pointer-events: none;
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
      backdrop-filter: blur(8px);
      animation: floatTooltip 2.2s infinite ease-in-out;
      transition: opacity 0.4s ease, transform 0.4s ease;
      white-space: nowrap;
    }
    
    body[data-on="true"] .cord-tooltip {
      opacity: 0;
      transform: translateY(-8px);
      pointer-events: none;
    }
    
    .tooltip-arrow {
      position: absolute;
      top: -5px;
      left: 50%;
      transform: translateX(-50%) rotate(45deg);
      width: 10px;
      height: 10px;
      background: rgba(16, 19, 25, 0.88);
      border-left: 1px solid rgba(255, 255, 255, 0.14);
      border-top: 1px solid rgba(255, 255, 255, 0.14);
    }
    
    @keyframes floatTooltip {
    
      0%,
      100% {
        transform: translateY(0);
      }
    
      50% {
        transform: translateY(-5px);
      }
    }
    
    /* Form Stage */
    .form-stage {
      flex: 1 1 420px;
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
      min-height: 520px;
    }
    
    /* Login Card */
    .login-card {
      display: none;
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
      width: 100%;
      max-width: 410px;
      background: var(--card-bg);
      backdrop-filter: blur(28px) saturate(180%);
      -webkit-backdrop-filter: blur(28px) saturate(180%);
      border: 1px solid var(--card-border);
      border-radius: 30px;
      padding: 2.5rem 2.2rem;
      box-shadow: 0 25px 60px rgba(0, 0, 0, 0.5);
      position: relative;
      overflow: hidden;
      transform: translateY(24px) scale(0.96);
      z-index: 10;
    }
    
    body[data-on="true"] .login-card {
      display: block;
      opacity: 1;
      visibility: visible;
      pointer-events: auto;
      transform: translateY(0) scale(1);
      box-shadow:
        -20px 0 60px -15px var(--beam-color),
        0 30px 65px rgba(0, 0, 0, 0.55),
        inset 0 1px 2px rgba(255, 255, 255, 0.2);
    }
    
    /* OFF State Priority */
    body[data-on="false"] .login-card {
      display: none !important;
      opacity: 0 !important;
      visibility: hidden !important;
      pointer-events: none !important;
    }
    
    body[data-on="false"] .svg-light-beam {
      opacity: 0 !important;
      visibility: hidden !important;
    }
    
    body[data-on="false"] .ambient-glow {
      opacity: 0 !important;
      visibility: hidden !important;
    }
    
    body[data-on="false"] .shade-reflector-on {
      opacity: 0 !important;
    }
    
    body[data-on="false"] .bulb-glow-core {
      opacity: 0 !important;
    }
    
    body[data-on="false"] .bulb-filament {
      stroke: #555 !important;
      filter: none !important;
    }
    
    /* Card Header */
    .card-header {
      margin-bottom: 1.6rem;
    }
    
    .card-title {
      font-size: 1.8rem;
      font-weight: 800;
      letter-spacing: -0.03em;
      color: #fff;
      margin-bottom: 0.35rem;
    }
    
    .card-subtitle {
      font-size: 0.88rem;
      color: var(--text-muted);
      line-height: 1.45;
    }
    
    /* Tabs: Sign In / Sign Up */
    .auth-tabs {
      position: relative;
      display: flex;
      background: rgba(0, 0, 0, 0.28);
      padding: 4px;
      border-radius: 16px;
      border: 1px solid rgba(255, 255, 255, 0.06);
      margin-bottom: 1.6rem;
    }
    
    .auth-tab {
      flex: 1;
      background: transparent;
      border: none;
      padding: 9px 0;
      color: var(--text-muted);
      font-family: inherit;
      font-size: 0.85rem;
      font-weight: 600;
      cursor: pointer;
      z-index: 2;
      transition: color 0.3s ease;
      text-align: center;
    }
    
    .auth-tab.active {
      color: #fff;
    }
    
    .tab-slider {
      position: absolute;
      top: 4px;
      bottom: 4px;
      left: 4px;
      width: calc(50% - 4px);
      background: rgba(255, 255, 255, 0.12);
      border-radius: 12px;
      transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
      z-index: 1;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
    }
    
    .auth-tabs[data-active="register"] .tab-slider {
      transform: translateX(100%);
    }
    
    /* Form Groups */
    .form-group {
      margin-bottom: 1.25rem;
    }
    
    .form-group label {
      display: block;
      font-size: 0.8rem;
      font-weight: 600;
      color: var(--text-muted);
      margin-bottom: 0.45rem;
    }
    
    .label-row {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 0.45rem;
    }
    
    .label-row label {
      margin-bottom: 0;
    }
    
    .forgot-link {
      font-size: 0.78rem;
      font-weight: 600;
      color: var(--lamp-accent);
      text-decoration: none;
      transition: opacity 0.2s ease;
    }
    
    .forgot-link:hover {
      text-decoration: underline;
      opacity: 0.85;
    }
    
    .input-wrapper {
      position: relative;
      display: flex;
      align-items: center;
      background: var(--input-bg);
      border: 1px solid var(--input-border);
      border-radius: 15px;
      transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
    }
    
    .input-wrapper:hover {
      border-color: rgba(255, 255, 255, 0.18);
      background: rgba(255, 255, 255, 0.06);
    }
    
    .input-wrapper:focus-within {
      border-color: var(--lamp-accent);
      background: rgba(255, 255, 255, 0.08);
      box-shadow: 0 0 0 3px var(--lamp-focus-glow);
    }
    
    .field-icon {
      position: absolute;
      left: 15px;
      width: 18px;
      height: 18px;
      color: var(--text-dim);
      pointer-events: none;
      transition: color 0.3s ease;
    }
    
    .input-wrapper:focus-within .field-icon {
      color: var(--lamp-accent);
    }
    
    .input-wrapper input {
      width: 100%;
      padding: 13px 42px 13px 44px;
      background: transparent;
      border: none;
      outline: none;
      color: #fff;
      font-size: 0.92rem;
      font-family: inherit;
      font-weight: 500;
    }
    
    .input-wrapper input::placeholder {
      color: var(--text-dim);
      font-weight: 400;
    }
    
    .eye-toggle {
      position: absolute;
      right: 14px;
      background: transparent;
      border: none;
      color: var(--text-dim);
      cursor: pointer;
      padding: 4px;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: color 0.2s ease;
    }
    
    .eye-toggle:hover {
      color: #fff;
    }
    
    .eye-icon {
      width: 18px;
      height: 18px;
    }
    
    /* Options */
    .options-row {
      margin-bottom: 1.4rem;
    }
    
    .custom-checkbox {
      display: inline-flex;
      align-items: center;
      gap: 9px;
      cursor: pointer;
    }
    
    .custom-checkbox input {
      display: none;
    }
    
    .checkbox-box {
      width: 18px;
      height: 18px;
      border-radius: 6px;
      background: rgba(255, 255, 255, 0.05);
      border: 1px solid rgba(255, 255, 255, 0.18);
      display: flex;
      align-items: center;
      justify-content: center;
      transition: all 0.25s ease;
    }
    
    .checkbox-box svg {
      width: 12px;
      height: 12px;
      color: #121417;
      opacity: 0;
      transform: scale(0.5);
      transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
    }
    
    .custom-checkbox input:checked+.checkbox-box {
      background: var(--lamp-accent);
      border-color: var(--lamp-accent);
    }
    
    .custom-checkbox input:checked+.checkbox-box svg {
      opacity: 1;
      transform: scale(1);
    }
    
    .checkbox-label {
      font-size: 0.82rem;
      color: var(--text-muted);
      font-weight: 500;
    }
    
    /* Submit Button */
    .submit-btn {
      position: relative;
      width: 100%;
      padding: 14px;
      border-radius: 15px;
      border: none;
      background: linear-gradient(135deg, var(--lamp-accent) 0%, var(--lamp-secondary) 100%);
      color: #0b0d10;
      font-family: inherit;
      font-size: 0.95rem;
      font-weight: 700;
      cursor: pointer;
      overflow: hidden;
      box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.4);
      transition: all 0.35s cubic-bezier(0.16, 1, 0.3, 1);
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .submit-btn:hover {
      transform: translateY(-2px);
      box-shadow: 0 14px 28px -5px rgba(0, 0, 0, 0.5), 0 0 25px rgba(255, 171, 61, 0.25);
    }
    
    .submit-btn:active {
      transform: translateY(0);
    }
    
    .btn-glow-layer {
      position: absolute;
      top: 0;
      left: -100%;
      width: 60%;
      height: 100%;
      background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
      transform: skewX(-20deg);
      transition: left 0.75s ease;
    }
    
    .submit-btn:hover .btn-glow-layer {
      left: 150%;
    }
    
    .btn-content {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
    }
    
    .btn-arrow {
      width: 18px;
      height: 18px;
      transition: transform 0.3s ease;
    }
    
    .submit-btn:hover .btn-arrow {
      transform: translateX(4px);
    }
    
    .btn-spinner {
      width: 20px;
      height: 20px;
      border: 2.5px solid rgba(0, 0, 0, 0.25);
      border-top-color: #000;
      border-radius: 50%;
      animation: spin 0.8s linear infinite;
    }
    
    @keyframes spin {
      to {
        transform: rotate(360deg);
      }
    }
    
    .btn-success-icon {
      width: 22px;
      height: 22px;
      color: #000;
    }
    
    /* Divider & Socials */
    .auth-divider {
      display: flex;
      align-items: center;
      gap: 12px;
      margin: 1.5rem 0 1.1rem 0;
    }
    
    .divider-line {
      flex: 1;
      height: 1px;
      background: rgba(255, 255, 255, 0.08);
    }
    
    .divider-text {
      font-size: 0.74rem;
      color: var(--text-dim);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.06em;
    }
    
    .social-row {
      display: flex;
      gap: 10px;
    }
    
    .social-btn {
      flex: 1;
      height: 42px;
      border-radius: 13px;
      background: rgba(255, 255, 255, 0.04);
      border: 1px solid rgba(255, 255, 255, 0.08);
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      transition: all 0.3s ease;
      color: #fff;
    }
    
    .social-btn svg {
      width: 19px;
      height: 19px;
    }
    
    .social-btn:hover {
      background: rgba(255, 255, 255, 0.1);
      border-color: rgba(255, 255, 255, 0.2);
      transform: translateY(-2px);
    }
    
    /* Success Overlay */
    .success-overlay {
      position: absolute;
      inset: 0;
      background: rgba(14, 18, 24, 0.95);
      backdrop-filter: blur(20px);
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 30px;
      padding: 2.5rem;
      z-index: 30;
      animation: fadeIn 0.4s ease;
    }
    
    @keyframes fadeIn {
      from {
        opacity: 0;
        transform: scale(0.95);
      }
    
      to {
        opacity: 1;
        transform: scale(1);
      }
    }
    
    .success-box {
      display: flex;
      flex-direction: column;
      align-items: center;
      text-align: center;
    }
    
    .success-ring {
      width: 60px;
      height: 60px;
      border-radius: 50%;
      background: rgba(46, 213, 115, 0.15);
      color: #2ed573;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-bottom: 1.1rem;
      border: 1px solid rgba(46, 213, 115, 0.3);
      box-shadow: 0 0 20px rgba(46, 213, 115, 0.2);
    }
    
    .success-ring svg {
      width: 30px;
      height: 30px;
    }
    
    .success-box h3 {
      font-size: 1.3rem;
      font-weight: 700;
      color: #fff;
      margin-bottom: 0.5rem;
    }
    
    .success-box p {
      font-size: 0.88rem;
      color: var(--text-muted);
      line-height: 1.5;
      margin-bottom: 1.4rem;
    }
    
    .reset-demo-btn {
      background: rgba(255, 255, 255, 0.08);
      border: 1px solid rgba(255, 255, 255, 0.15);
      color: #fff;
      padding: 9px 22px;
      border-radius: 20px;
      font-family: inherit;
      font-size: 0.85rem;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.3s ease;
    }
    
    .reset-demo-btn:hover {
      background: #fff;
      color: #000;
    }
    
    /* Responsive */
    @media (max-width: 960px) {
      .scene-container {
        flex-direction: column;
        padding-top: 60px;
        gap: 1.5rem;
      }
    
      .lamp-stage {
        flex: 0 0 auto;
        height: 340px;
      }
    
      .lamp-wrapper {
        width: 320px;
        height: 380px;
        transform: scale(0.9);
      }
    
      .form-stage {
        width: 100%;
        min-height: auto;
      }
    
      .login-card {
        max-width: 100%;
        padding: 2rem 1.8rem;
      }
    }
    
    @media (max-width: 480px) {
      .scene-container {
        padding: 40px 1rem 1.5rem 1rem;
      }
    
      .login-card {
        border-radius: 24px;
        padding: 1.8rem 1.3rem;
      }
    
      .card-title {
        font-size: 1.5rem;
      }
    }

    JS :

    Makes the lamp login page interactive by allowing users to pull the string to turn the lamp on or off, change lamp colors, toggle sound effects, and see animated light and dust particles. It also controls the Sign In and Sign Up tabs, password visibility, simulated login success, button animations, and 3D card tilt effects using GSAP. The login process is only a demo and does not authenticate real users.

    document.addEventListener("DOMContentLoaded", () => {
      gsap.registerPlugin(Draggable);
    
      // DOM Elements
      const body = document.body;
      const cordBead = document.getElementById("cordBead");
      const cordHit = document.getElementById("cordHit");
      const elasticCord = document.getElementById("elasticCord");
      const shadeAssembly = document.getElementById("shadeAssembly");
      const soundToggle = document.getElementById("soundToggle");
      const soundOnIcon = soundToggle.querySelector(".sound-on");
      const soundOffIcon = soundToggle.querySelector(".sound-off");
    
      // Form Elements
      const loginCard = document.getElementById("loginCard");
      const tabSignIn = document.getElementById("tabSignIn");
      const tabRegister = document.getElementById("tabRegister");
      const authTabs = document.querySelector(".auth-tabs");
      const cardTitle = document.querySelector(".card-title");
      const cardSubtitle = document.querySelector(".card-subtitle");
      const submitBtn = document.getElementById("submitBtn");
      const btnText = submitBtn.querySelector(".btn-text");
      const btnSpinner = document.getElementById("btnSpinner");
      const btnSuccess = document.getElementById("btnSuccess");
      const btnArrow = submitBtn.querySelector(".btn-arrow");
      const eyeToggle = document.getElementById("eyeToggle");
      const passField = document.getElementById("passField");
      const eyeShow = eyeToggle.querySelector(".eye-show");
      const eyeHide = eyeToggle.querySelector(".eye-hide");
      const successOverlay = document.getElementById("successOverlay");
      const resetDemoBtn = document.getElementById("resetDemoBtn");
    
      // State
      let isOn = false;
      let isSoundEnabled = true;
      let activeTab = "signin";
      let isSimulatingPull = false;
    
      // Elastic String Geometry
      const ANCHOR_X = 245;
      const ANCHOR_Y = 212;
      const REST_X = 245;
      const REST_Y = 300;
      const MAX_STRETCH = 120;
      const TRIGGER_PULL = 32;
    
      gsap.set(cordBead, { x: REST_X, y: REST_Y });
    
      let twangAmp = 0;
      let twangStartTime = 0;
    
      function renderElasticString(curX, curY) {
        let twangOffset = 0;
        if (twangAmp > 0.05) {
          const elapsed = performance.now() - twangStartTime;
          twangOffset = Math.sin(elapsed * 0.05) * twangAmp;
        }
    
        const midX = (ANCHOR_X + curX) / 2 + twangOffset;
        const midY = (ANCHOR_Y + curY) / 2;
    
        // Dynamic rubber cord thinning as it stretches
        const stretchRatio = Math.max(1, (curY - ANCHOR_Y) / (REST_Y - ANCHOR_Y));
        const strokeWidth = Math.max(1.6, 2.6 / Math.sqrt(stretchRatio));
    
        elasticCord.setAttribute("d", `M ${ANCHOR_X} ${ANCHOR_Y} Q ${midX} ${midY} ${curX} ${curY}`);
        elasticCord.setAttribute("stroke-width", strokeWidth.toFixed(2));
      }
    
      // Web Audio Synthesizer
      let audioCtx = null;
    
      function initAudio() {
        if (!audioCtx) {
          const AudioContext = window.AudioContext || window.webkitAudioContext;
          if (AudioContext) audioCtx = new AudioContext();
        }
        if (audioCtx && audioCtx.state === "suspended") {
          audioCtx.resume();
        }
      }
    
      function playElasticPluckSound(pullDist, turningOn) {
        if (!isSoundEnabled) return;
        try {
          initAudio();
          if (!audioCtx) return;
    
          const now = audioCtx.currentTime;
    
          // Pluck tone
          const osc = audioCtx.createOscillator();
          const oscGain = audioCtx.createGain();
          osc.type = "triangle";
    
          const startFreq = 480 + Math.min(260, pullDist * 3);
          osc.frequency.setValueAtTime(startFreq, now);
          osc.frequency.exponentialRampToValueAtTime(140, now + 0.12);
    
          oscGain.gain.setValueAtTime(0.4, now);
          oscGain.gain.exponentialRampToValueAtTime(0.001, now + 0.14);
    
          osc.connect(oscGain);
          oscGain.connect(audioCtx.destination);
          osc.start(now);
          osc.stop(now + 0.15);
    
          // Switch snap
          if (pullDist >= TRIGGER_PULL) {
            const snap = audioCtx.createOscillator();
            const snapGain = audioCtx.createGain();
            snap.type = "sine";
            snap.frequency.setValueAtTime(turningOn ? 1800 : 1500, now + 0.02);
            snap.frequency.exponentialRampToValueAtTime(320, now + 0.06);
    
            snapGain.gain.setValueAtTime(0.35, now + 0.02);
            snapGain.gain.exponentialRampToValueAtTime(0.001, now + 0.065);
    
            snap.connect(snapGain);
            snapGain.connect(audioCtx.destination);
            snap.start(now + 0.02);
            snap.stop(now + 0.07);
    
            // Power hum
            if (turningOn) {
              const hum = audioCtx.createOscillator();
              const humGain = audioCtx.createGain();
              hum.type = "sine";
              hum.frequency.setValueAtTime(120, now + 0.05);
              humGain.gain.setValueAtTime(0.001, now);
              humGain.gain.linearRampToValueAtTime(0.06, now + 0.08);
              humGain.gain.exponentialRampToValueAtTime(0.001, now + 0.35);
    
              hum.connect(humGain);
              humGain.connect(audioCtx.destination);
              hum.start(now + 0.05);
              hum.stop(now + 0.38);
            }
          }
        } catch (e) {
          console.warn("AudioContext error:", e);
        }
      }
    
      // Sound Toggle
      soundToggle.addEventListener("click", () => {
        isSoundEnabled = !isSoundEnabled;
        soundOnIcon.classList.toggle("hidden", !isSoundEnabled);
        soundOffIcon.classList.toggle("hidden", isSoundEnabled);
        if (isSoundEnabled) initAudio();
      });
    
      function playColorSwitchSound() {
        if (!isSoundEnabled) return;
        try {
          initAudio();
          if (!audioCtx) return;
          const now = audioCtx.currentTime;
          const osc = audioCtx.createOscillator();
          const gain = audioCtx.createGain();
          osc.type = "sine";
          osc.frequency.setValueAtTime(880, now);
          osc.frequency.exponentialRampToValueAtTime(1320, now + 0.05);
          gain.gain.setValueAtTime(0.12, now);
          gain.gain.exponentialRampToValueAtTime(0.001, now + 0.06);
          osc.connect(gain);
          gain.connect(audioCtx.destination);
          osc.start(now);
          osc.stop(now + 0.07);
        } catch (e) { }
      }
    
      // Color Palette Switcher
      const colorDots = document.querySelectorAll(".color-dot-btn");
      let currentColor = "amber";
    
      colorDots.forEach((btn) => {
        btn.addEventListener("click", () => {
          const selectedColor = btn.getAttribute("data-color");
          if (selectedColor === currentColor) return;
    
          colorDots.forEach((d) => d.classList.remove("active"));
          btn.classList.add("active");
    
          currentColor = selectedColor;
          body.setAttribute("data-color", currentColor);
          activeParticleTheme = particleThemes[currentColor] || particleThemes.amber;
    
          playColorSwitchSound();
    
          if (isOn) {
            gsap.fromTo(".svg-light-beam, .ambient-glow",
              { opacity: 0.65 },
              {
                opacity: 1,
                duration: 0.45,
                ease: "power1.out",
                onComplete: () => {
                  gsap.set([".svg-light-beam", ".ambient-glow"], { clearProps: "opacity,visibility" });
                }
              }
            );
          }
        });
      });
    
      // Elastic Cord Draggable Interaction
      Draggable.create(cordBead, {
        type: "x,y",
        bounds: {
          minY: REST_Y,
          maxY: REST_Y + MAX_STRETCH,
          minX: REST_X - 45,
          maxX: REST_X + 45,
        },
        cursor: "grab",
        activeCursor: "grabbing",
        onPress() {
          initAudio();
          twangAmp = 0;
        },
        onDrag() {
          renderElasticString(this.x, this.y);
    
          // Shade tilts slightly under tension
          const pullDist = this.y - REST_Y;
          const shadeTilt = (pullDist / MAX_STRETCH) * 1.8;
          gsap.set(shadeAssembly, {
            rotation: shadeTilt,
            transformOrigin: "215px 175px"
          });
        },
        onRelease() {
          handleElasticRelease(this.x, this.y);
        }
      });
    
      function handleElasticRelease(curX, curY) {
        const pullDist = curY - REST_Y;
        const isTriggered = pullDist >= TRIGGER_PULL;
    
        if (isTriggered) {
          toggleLamp();
        }
    
        playElasticPluckSound(pullDist, isOn);
    
        // Bead rebound snap
        gsap.to(cordBead, {
          x: REST_X,
          y: REST_Y,
          duration: 1.15,
          ease: "elastic.out(2.2, 0.16)",
          onUpdate: () => {
            const bx = gsap.getProperty(cordBead, "x");
            const by = gsap.getProperty(cordBead, "y");
            renderElasticString(bx, by);
          }
        });
    
        // String twang vibration
        twangAmp = (curX - REST_X) * 0.4 + (pullDist * 0.3);
        twangStartTime = performance.now();
        gsap.to({ val: twangAmp }, {
          val: 0,
          duration: 0.9,
          ease: "power2.out",
          onUpdate: function () {
            twangAmp = this.targets()[0].val;
          }
        });
    
        // Shade bounce back
        gsap.to(shadeAssembly, {
          rotation: 0,
          duration: 0.7,
          ease: "back.out(2.2)",
          transformOrigin: "215px 175px"
        });
      }
    
      // Pull cord click trigger
      cordHit.addEventListener("click", () => {
        if (isSimulatingPull) return;
        performSimulatedPull();
      });
    
      function performSimulatedPull() {
        isSimulatingPull = true;
        initAudio();
    
        gsap.to(cordBead, {
          y: REST_Y + 50,
          duration: 0.22,
          ease: "power2.in",
          onUpdate: () => {
            const by = gsap.getProperty(cordBead, "y");
            renderElasticString(REST_X, by);
          },
          onComplete: () => {
            handleElasticRelease(REST_X, REST_Y + 50);
            setTimeout(() => {
              isSimulatingPull = false;
            }, 500);
          }
        });
    
        gsap.to(shadeAssembly, {
          rotation: 1.8,
          duration: 0.22,
          ease: "power2.in",
          transformOrigin: "230px 188px"
        });
      }
    
      // Lamp State Controller
      function toggleLamp() {
        setLampState(!isOn);
      }
    
      function setLampState(targetState) {
        isOn = targetState;
        body.setAttribute("data-on", isOn ? "true" : "false");
    
        gsap.killTweensOf([
          ".bulb-glow-core",
          ".bulb-filament",
          ".svg-light-beam",
          ".ambient-glow",
          ".shade-reflector-on",
          loginCard,
          "#loginCard *"
        ]);
    
        gsap.set([".svg-light-beam", ".ambient-glow", ".shade-reflector-on"], { clearProps: "opacity,visibility" });
    
        const filament = document.querySelector(".bulb-filament");
        const bulbGlow = document.querySelector(".bulb-glow-core");
    
        if (isOn) {
          // Lamp ON
          gsap.timeline()
            .to(filament, { stroke: "#fff", duration: 0.05 })
            .to(bulbGlow, { opacity: 0.95, duration: 0.1, ease: "power2.out" });
    
          gsap.fromTo(loginCard,
            { y: 24, scale: 0.96, opacity: 0 },
            { y: 0, scale: 1, opacity: 1, duration: 0.5, ease: "power2.out" }
          );
    
          gsap.fromTo(
            ".card-header, .auth-tabs, .form-group, .options-row, .submit-btn, .auth-divider, .social-row",
            { y: 14, opacity: 0 },
            { y: 0, opacity: 1, duration: 0.45, stagger: 0.04, ease: "power2.out", delay: 0.08 }
          );
        } else {
          // Lamp OFF
          gsap.set(bulbGlow, { opacity: 0, clearProps: "opacity" });
          gsap.set(filament, { stroke: "#555", filter: "none", clearProps: "all" });
    
          gsap.to(loginCard, {
            y: 16,
            opacity: 0,
            scale: 0.96,
            duration: 0.22,
            ease: "power2.in",
            onComplete: () => {
              gsap.set(loginCard, { clearProps: "all" });
            }
          });
    
          gsap.set(loginCard, { rotateX: 0, rotateY: 0 });
        }
      }
    
      // Canvas Dust Particles
      const canvas = document.getElementById("dustCanvas");
      const ctx = canvas.getContext("2d");
      let width, height;
      let particles = [];
      const PARTICLE_COUNT = 60;
    
      const particleThemes = {
        amber: { fill: "255, 205, 120", glow: "255, 185, 80" },
        cyan: { fill: "140, 245, 255", glow: "0, 240, 255" },
        rose: { fill: "255, 160, 200", glow: "255, 51, 133" },
        mint: { fill: "160, 255, 200", glow: "0, 230, 118" },
        moonlight: { fill: "220, 235, 255", glow: "200, 220, 255" }
      };
      let activeParticleTheme = particleThemes.amber;
    
      function resizeCanvas() {
        width = canvas.width = window.innerWidth;
        height = canvas.height = window.innerHeight;
      }
      window.addEventListener("resize", resizeCanvas);
      resizeCanvas();
    
      class Particle {
        constructor() {
          this.reset();
        }
        reset() {
          this.x = Math.random() * width;
          this.y = Math.random() * height;
          this.radius = Math.random() * 2 + 0.6;
          this.vx = (Math.random() - 0.4) * 0.35;
          this.vy = -Math.random() * 0.4 - 0.15;
          this.alpha = Math.random() * 0.6 + 0.2;
          this.pulseSpeed = Math.random() * 0.03 + 0.01;
          this.pulse = Math.random() * Math.PI;
        }
        update() {
          this.x += this.vx;
          this.y += this.vy;
          this.pulse += this.pulseSpeed;
          if (this.y < 0) this.y = height;
          if (this.x < 0) this.x = width;
          if (this.x > width) this.x = 0;
        }
        draw() {
          const currentAlpha = (Math.sin(this.pulse) * 0.3 + 0.7) * this.alpha;
          const factor = isOn ? 1 : 0.08;
          ctx.save();
          ctx.beginPath();
          ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
          ctx.fillStyle = `rgba(${activeParticleTheme.fill}, ${currentAlpha * factor})`;
          if (isOn) {
            ctx.shadowBlur = 7;
            ctx.shadowColor = `rgba(${activeParticleTheme.glow}, 0.5)`;
          }
          ctx.fill();
          ctx.restore();
        }
      }
    
      for (let i = 0; i < PARTICLE_COUNT; i++) {
        particles.push(new Particle());
      }
    
      function renderParticles() {
        ctx.clearRect(0, 0, width, height);
        for (let i = 0; i < particles.length; i++) {
          particles[i].update();
          particles[i].draw();
        }
        requestAnimationFrame(renderParticles);
      }
      renderParticles();
    
      // Form Tabs & Controls
      tabSignIn.addEventListener("click", () => switchTab("signin"));
      tabRegister.addEventListener("click", () => switchTab("register"));
    
      function switchTab(tab) {
        if (activeTab === tab) return;
        activeTab = tab;
        authTabs.setAttribute("data-active", tab);
    
        tabSignIn.classList.toggle("active", tab === "signin");
        tabRegister.classList.toggle("active", tab === "register");
    
        if (tab === "signin") {
          cardTitle.textContent = "Welcome";
          cardSubtitle.textContent = "Sign in to continue to your account";
          btnText.textContent = "Sign In";
        } else {
          cardTitle.textContent = "Sign Up";
          cardSubtitle.textContent = "Create an account to get started";
          btnText.textContent = "Create Account";
        }
    
        gsap.fromTo(".card-title, .card-subtitle",
          { opacity: 0.6, y: -4 },
          { opacity: 1, y: 0, duration: 0.3, ease: "power2.out" }
        );
      }
    
      // Password Visibility Toggle
      eyeToggle.addEventListener("click", () => {
        const isPassword = passField.getAttribute("type") === "password";
        passField.setAttribute("type", isPassword ? "text" : "password");
        eyeShow.classList.toggle("hidden", isPassword);
        eyeHide.classList.toggle("hidden", !isPassword);
      });
    
      // Submit Button
      submitBtn.addEventListener("click", (e) => {
        e.preventDefault();
        if (!isOn) {
          performSimulatedPull();
          return;
        }
    
        btnText.classList.add("hidden");
        btnArrow.classList.add("hidden");
        btnSpinner.classList.remove("hidden");
        submitBtn.style.pointerEvents = "none";
    
        setTimeout(() => {
          btnSpinner.classList.add("hidden");
          btnSuccess.classList.remove("hidden");
    
          setTimeout(() => {
            successOverlay.classList.remove("hidden");
            btnText.classList.remove("hidden");
            btnArrow.classList.remove("hidden");
            btnSuccess.classList.add("hidden");
            submitBtn.style.pointerEvents = "auto";
          }, 600);
        }, 1100);
      });
    
      // Reset Demo Modal
      resetDemoBtn.addEventListener("click", () => {
        successOverlay.classList.add("hidden");
        document.getElementById("userField").value = "";
        document.getElementById("passField").value = "";
      });
    
      // 3D Tilt on Mouse Move
      const card = document.getElementById("loginCard");
      const formStage = document.querySelector(".form-stage");
    
      formStage.addEventListener("mousemove", (e) => {
        if (!isOn) return;
        const rect = formStage.getBoundingClientRect();
        const x = e.clientX - rect.left - rect.width / 2;
        const y = e.clientY - rect.top - rect.height / 2;
    
        gsap.to(card, {
          rotateX: -(y / rect.height) * 9,
          rotateY: (x / rect.width) * 9,
          duration: 0.5,
          ease: "power1.out",
          transformPerspective: 900
        });
      });
    
      formStage.addEventListener("mouseleave", () => {
        gsap.to(card, {
          rotateX: 0,
          rotateY: 0,
          duration: 0.7,
          ease: "power2.out"
        });
      });
    
      // Render initial string
      renderElasticString(REST_X, REST_Y);
    });
    

    Conclusion

    In this project, we created a creative Lamp Login Animation using HTML, CSS, and JavaScript. By combining SVG graphics, GSAP animations, and modern CSS effects, we built an interactive login page where pulling the lamp cord reveals the login form with smooth transitions. This project is a great way to practice animations, DOM manipulation, event handling, and creating engaging user interfaces.

    If your project has problems, don’t worry. Just click to download the source code and face your coding challenges with excitement. Have fun coding!

    Animation loader loading preloader
    Share. Copy Link Twitter Facebook LinkedIn Email WhatsApp
    Previous ArticleHow to make 3D Globe with Location Pointer using HTML CSS and JavaScript
    Coding Stella
    • Website

    Related Posts

    JavaScript

    How to make 3D Globe with Location Pointer using HTML CSS and JavaScript

    15 October 2026
    JavaScript

    How to create Valentine’s Love Button Animation using HTML CSS and JS

    13 October 2026
    JavaScript

    How to make The Quantum Clock using HTML CSS and JavaScript

    7 October 2026
    Add A Comment
    Leave A Reply Cancel Reply

    Trending Post

    Master Frontend in 100 Days Ebook

    2 March 202432K Views

    How to make Modern Login Form using HTML & CSS | Glassmorphism

    11 January 202431K Views

    How to make I love you Animation in HTML CSS & JavaScript

    14 February 202424K Views

    How to make Valentine’s Day Card using HTML & CSS

    13 February 202415K Views
    Follow Us
    • Instagram
    • Facebook
    • YouTube
    • Twitter
    Featured Post

    How to make Download Button with Progress bar in HTML CSS & JavaScript

    15 February 2024

    How to create Animated No Chill Login form using HTML CSS and JS

    22 May 2025

    How to make Dynamic Glassmorphism Login Form using HTML & CSS

    14 August 2024

    How to make Animated Login Form using HTML & CSS

    14 February 2024

    How to make Interactive Login Form Lamp using HTML CSS JS

    19 October 2026

    How to make 3D Globe with Location Pointer using HTML CSS and JavaScript

    15 October 2026

    How to create Valentine’s Love Button Animation using HTML CSS and JS

    13 October 2026

    How to make The Quantum Clock using HTML CSS and JavaScript

    7 October 2026
    Facebook X (Twitter) Instagram YouTube
    • About Us
    • Privacy Policy
    • Return and Refund Policy
    • Terms and Conditions
    • Contact Us
    • Buy me a coffee
    © 2026 Coding Stella. Made with đŸ’™ by @coding.stella

    Type above and press Enter to search. Press Esc to cancel.