Cute Lamp Login Page

Looking for a fun, interactive way to spice up a dark-themed UI? Today, we are building a "Cute Lamp" login page.

This single-file solution features a fully scalable SVG cartoon lamp with changing expressions, smooth color-shifting neon glows, and a pull-string interaction cycle that toggles the light and the UI theme! Below is the complete HTML, CSS, and JavaScript code. Just copy it and save it as an .html file.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cute Lamp Interactive Login</title>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');

        :root {
            --bg-color: #0b0f14;
            --font-family: 'Poppins', sans-serif;
            --theme-color: #2a2c30;
            --theme-glow-rgb: 42, 44, 48;
            --shade-color: #2c2c2c;
            --bulb-color: #1a1a1a;
            --light-opacity: 0;
            --btn-text-color: #888;
            --btn-bg: #2a2c30;
        }

        * { margin: 0; padding: 0; box-sizing: border-box; }

        body {
            background-color: var(--bg-color);
            color: #ffffff;
            font-family: var(--font-family);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            overflow-x: hidden;
        }

        .container {
            display: flex; width: 100%; max-width: 1100px;
            height: 600px; padding: 2rem; gap: 2rem;
        }

        .lamp-section {
            flex: 1; display: flex; justify-content: center;
            align-items: center; position: relative;
        }

        .lamp-svg {
            width: 100%; max-width: 350px; height: auto;
            overflow: visible; filter: drop-shadow(0 20px 30px rgba(0,0,0,0.5));
        }

        .shade-main { fill: var(--shade-color); transition: fill 0.6s ease; }
        .shade-inner { fill: var(--bulb-color); transition: fill 0.6s ease; }
        .light-cone { opacity: var(--light-opacity); transition: opacity 0.6s ease; }
        .face-sleep { transition: opacity 0.3s ease; }
        .face-awake { opacity: 0; transition: opacity 0.3s ease; }

        .pull-string-group {
            cursor: pointer; transform-origin: top;
            transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
        }
        .pull-string-group:hover .string-handle { stroke: #ffffff; }

        .lamp-ambient-glow {
            position: absolute; width: 300px; height: 300px;
            background: radial-gradient(circle, rgba(var(--theme-glow-rgb), 0.15) 0%, transparent 70%);
            top: 50%; left: 50%; transform: translate(-50%, -50%);
            z-index: -1; transition: background 0.6s ease; pointer-events: none;
        }

        .login-section { flex: 1; display: flex; justify-content: center; align-items: center; }

        .login-card {
            width: 100%; max-width: 400px;
            background: rgba(18, 24, 32, 0.6); backdrop-filter: blur(12px);
            padding: 3rem 2.5rem; border-radius: 20px;
            border: 2px solid var(--theme-color);
            box-shadow: 0 0 30px rgba(var(--theme-glow-rgb), 0.15), inset 0 0 15px rgba(255, 255, 255, 0.02);
            transition: border-color 0.6s ease, box-shadow 0.6s ease;
        }

        .login-card h2 { font-size: 2rem; font-weight: 600; text-align: center; margin-bottom: 2rem; }
        .input-group { margin-bottom: 1.5rem; display: flex; flex-direction: column; }
        .input-group label { font-size: 0.85rem; color: #a0a0a0; margin-bottom: 0.5rem; font-weight: 500; }
        
        .input-group input {
            background: #151a21; border: 1px solid #2a2c30;
            padding: 1rem 1.2rem; border-radius: 10px; color: #fff; outline: none;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .input-group input:focus {
            border-color: var(--theme-color);
            box-shadow: 0 0 10px rgba(var(--theme-glow-rgb), 0.3);
        }

        .login-btn {
            width: 100%; padding: 1rem; border: none; border-radius: 10px;
            background: var(--btn-bg); color: var(--btn-text-color);
            font-size: 1rem; font-weight: 600; cursor: pointer;
            margin-top: 1rem; transition: all 0.4s ease;
        }
        .login-btn:hover { filter: brightness(1.1); transform: translateY(-2px); }
        .forgot-pass { display: block; text-align: center; margin-top: 1.5rem; color: #777; text-decoration: none; }
        .forgot-pass:hover { color: #fff; }

        @media (max-width: 768px) {
            .container { flex-direction: column; height: auto; }
            .lamp-svg { max-width: 250px; }
        }
    </style>
</head>
<body>

    <div class="container">
        <div class="lamp-section">
            <div class="lamp-ambient-glow"></div>
            <svg class="lamp-svg" viewBox="0 0 300 450" xmlns="http://www.w3.org/2000/svg">
                <defs>
                    <linearGradient id="lightConeGrad" x1="0%" y1="0%" x2="0%" y2="100%">
                        <stop offset="0%" stop-color="#ffffff" stop-opacity="0.8" />
                        <stop offset="100%" stop-color="#ffffff" stop-opacity="0" />
                    </linearGradient>
                    <clipPath id="mouthClip">
                        <path d="M 125 155 Q 150 190 175 155 Z" />
                    </clipPath>
                </defs>

                <polygon points="90,180 210,180 320,450 -20,450" fill="url(#lightConeGrad)" class="light-cone" />
                <ellipse cx="150" cy="400" rx="60" ry="15" fill="#151515" />
                <ellipse cx="150" cy="395" rx="60" ry="15" fill="#3a3c40" />
                <rect x="140" y="180" width="20" height="220" fill="#2a2c30" />
                <rect x="142" y="180" width="8" height="220" fill="#4a4c50" /> 
                <ellipse cx="150" cy="175" rx="90" ry="20" class="shade-inner" />

                <g class="pull-string-group" onclick="toggleLamp()">
                    <line x1="105" y1="180" x2="105" y2="280" stroke="#555" stroke-width="3" />
                    <line x1="105" y1="280" x2="105" y2="310" stroke="#888" stroke-width="6" stroke-linecap="round" class="string-handle" />
                </g>

                <path d="M 95 60 Q 150 45 205 60 L 240 175 Q 150 195 60 175 Z" class="shade-main" />

                <g class="face-sleep">
                    <path d="M 115 130 Q 125 140 135 130" stroke="#111" stroke-width="4" fill="none" stroke-linecap="round" />
                    <path d="M 165 130 Q 175 140 185 130" stroke="#111" stroke-width="4" fill="none" stroke-linecap="round" />
                </g>

                <g class="face-awake">
                    <path d="M 115 130 Q 125 115 135 130" stroke="#111" stroke-width="4" fill="none" stroke-linecap="round" />
                    <path d="M 165 130 Q 175 115 185 130" stroke="#111" stroke-width="4" fill="none" stroke-linecap="round" />
                    <g>
                        <path d="M 125 155 Q 150 190 175 155 Z" fill="#111" />
                        <path d="M 140 165 Q 150 190 160 165 Z" fill="#f87171" clip-path="url(#mouthClip)" />
                    </g>
                </g>
            </svg>
        </div>

        <div class="login-section">
            <div class="login-card">
                <h2>Welcome Back</h2>
                <form onsubmit="event.preventDefault();">
                    <div class="input-group">
                        <label>Username</label>
                        <input type="text" placeholder="Enter your username">
                    </div>
                    <div class="input-group">
                        <label>Password</label>
                        <input type="password" placeholder="Enter your password">
                    </div>
                    <button type="submit" class="login-btn">Login</button>
                </form>
                <a href="#" class="forgot-pass">Forgot Password?</a>
            </div>
        </div>
    </div>

    <script>
        const lampStates = [
            { lamp: "OFF", themeColor: "#2a2c30", themeGlowRGB: "42, 44, 48", shadeColor: "#2c2c2c", bulbColor: "#1a1a1a", lightOpacity: "0", btnBg: "#2a2c30", btnText: "#888", faceAwakeOpacity: "0", faceSleepOpacity: "1" },
            { lamp: "ON", themeColor: "#22c55e", themeGlowRGB: "34, 197, 94", shadeColor: "#6c8c73", bulbColor: "#e6ffe6", lightOpacity: "0.15", btnBg: "#22c55e", btnText: "#fff", faceAwakeOpacity: "1", faceSleepOpacity: "0" },
            { lamp: "OFF", themeColor: "#2a2c30", themeGlowRGB: "42, 44, 48", shadeColor: "#2c2c2c", bulbColor: "#1a1a1a", lightOpacity: "0", btnBg: "#2a2c30", btnText: "#888", faceAwakeOpacity: "0", faceSleepOpacity: "1" },
            { lamp: "ON", themeColor: "#f97316", themeGlowRGB: "249, 115, 22", shadeColor: "#947463", bulbColor: "#fff0e6", lightOpacity: "0.15", btnBg: "#f97316", btnText: "#fff", faceAwakeOpacity: "1", faceSleepOpacity: "0" }
        ];

        let currentStateIndex = 0;
        const pullString = document.querySelector('.pull-string-group');
        const rootStyles = document.documentElement.style;
        const faceAwake = document.querySelector('.face-awake');
        const faceSleep = document.querySelector('.face-sleep');

        function toggleLamp() {
            pullString.style.transform = 'translateY(15px)';
            setTimeout(() => { pullString.style.transform = 'translateY(0)'; }, 150);

            currentStateIndex = (currentStateIndex + 1) % lampStates.length;
            const config = lampStates[currentStateIndex];

            rootStyles.setProperty('--theme-color', config.themeColor);
            rootStyles.setProperty('--theme-glow-rgb', config.themeGlowRGB);
            rootStyles.setProperty('--shade-color', config.shadeColor);
            rootStyles.setProperty('--bulb-color', config.bulbColor);
            rootStyles.setProperty('--light-opacity', config.lightOpacity);
            rootStyles.setProperty('--btn-bg', config.btnBg);
            rootStyles.setProperty('--btn-text-color', config.btnText);

            faceAwake.style.opacity = config.faceAwakeOpacity;
            faceSleep.style.opacity = config.faceSleepOpacity;
        }
    </script>
</body>
</html>

Live Preview

Comments

Popular posts from this blog

Header Animation | Bold Text & 3D Effect | CSS Tutorial|Cursor animation effect using html css js

Portfolio website