Close Menu

    Subscribe to Updates

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

    What's Hot

    How to make Robot Login Form in HTML CSS & JavaScript

    5 August 2026

    How to make Password Input Light in HTML CSS & JavaScript

    1 August 2026

    How to create 3D Toons Carousel Slider using HTML CSS and JS

    29 July 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 Robot Login Form in HTML CSS & JavaScript
    JavaScript

    How to make Robot Login Form in HTML CSS & JavaScript

    Coding StellaBy Coding Stella5 August 2026No Comments17 Mins Read
    Share Facebook Twitter Pinterest LinkedIn Tumblr Reddit Email WhatsApp Copy Link

    How to Make a Robot Login Form in HTML, CSS & JavaScript

    Let’s create a fun and interactive Robot Login Form using HTML, CSS, and JavaScript. This project features an animated robot that reacts to user actions, such as following the cursor, changing expressions while typing, turning away when entering a password, and celebrating with a success animation after login.

    We’ll use:

    • HTML to build the robot, login form, input fields, and button.
    • CSS to design the robot, create smooth animations, add stylish UI elements, and make the form responsive.
    • JavaScript to bring the robot to life by controlling eye movement, facial expressions, speech bubble messages, password visibility, form validation, password strength meter, and success animations.

    Whether you’re a beginner or an experienced developer, this project is a great way to learn how to combine animations, DOM manipulation, and interactive UI design to create an engaging login experience. Let’s get started and build your own animated Robot Login Form! 🤖🔐

    HTML :

    The HTML creates the structure of the login page. It contains the robot, speech bubble, login form, input fields for name, email, and password, and the login button. Each element has a class or ID so it can be styled with CSS and controlled with JavaScript.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8" />
      <title>Robot Login Form | @coding.stella</title>
      <link rel="stylesheet" href="/style.css" />
    </head>
    
    <body>
      <div class="scene">
        <main class="stage" id="stage">
          <div class="robot" id="robot" data-mood="idle">
            <div class="bubble" id="bubble" role="status" aria-live="polite">
              <span id="bubbleText">Hi. I'm Volt. I guard this form.</span>
            </div>
    
            <div class="antenna" aria-hidden="true">
              <span class="antenna-rod"></span>
              <span class="antenna-tip"></span>
            </div>
    
            <div class="head3d" aria-hidden="true">
              <div class="head" id="head">
                <span class="ear ear--l"></span>
                <span class="ear ear--r"></span>
    
                <div class="face face--front">
                  <div class="visor">
                    <div class="eyes" id="eyes">
                      <span class="eye eye--l"></span>
                      <span class="eye eye--r"></span>
                    </div>
                    <span class="cheek cheek--l"></span>
                    <span class="cheek cheek--r"></span>
                    <span class="mouth"></span>
                  </div>
                </div>
    
                <div class="face face--back">
                  <div class="panel">
                    <span class="panel-lights"><i></i><i></i><i></i></span>
                    <div class="meter" id="meter">
                      <i></i><i></i><i></i><i></i>
                    </div>
                    <p class="panel-label" id="panelLabel">NOT LOOKING</p>
                  </div>
                </div>
              </div>
            </div>
          </div>
    
          <form class="card" id="form" novalidate>
            <span class="hand hand--l" aria-hidden="true"></span>
            <span class="hand hand--r" aria-hidden="true"></span>
    
            <h1 class="title">Beep boop. Who goes there?</h1>
    
            <label class="field">
              <svg class="field-icon" viewBox="0 0 24 24" aria-hidden="true">
                <path d="M12 12a4.5 4.5 0 1 0-4.5-4.5A4.5 4.5 0 0 0 12 12Zm0 2c-3.9 0-8 2-8 5v1.5h16V19c0-3-4.1-5-8-5Z" />
              </svg>
              <input id="name" type="text" placeholder="Your name" autocomplete="name" aria-label="Your name" />
            </label>
    
            <label class="field">
              <svg class="field-icon" viewBox="0 0 24 24" aria-hidden="true">
                <path
                  d="M4 5h16a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2Zm8 7.3L4.4 7h15.2L12 12.3ZM4 9.2V17h16V9.2l-8 5.3-8-5.3Z" />
              </svg>
              <input id="email" type="email" placeholder="Your email" autocomplete="email" aria-label="Your email" />
            </label>
    
            <label class="field">
              <svg class="field-icon" viewBox="0 0 24 24" aria-hidden="true">
                <path
                  d="M12 2a5 5 0 0 0-5 5v3H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8a2 2 0 0 0-2-2h-1V7a5 5 0 0 0-5-5Zm-3 8V7a3 3 0 0 1 6 0v3H9Zm3 4a2 2 0 0 1 1 3.7V19h-2v-1.3a2 2 0 0 1 1-3.7Z" />
              </svg>
              <input id="password" type="password" placeholder="Super secret password" autocomplete="new-password"
                aria-label="Password" />
              <button class="peek" id="togglePass" type="button" aria-label="Show password" aria-pressed="false">
                <svg viewBox="0 0 24 24" aria-hidden="true">
                  <path
                    d="M12 5c-5 0-9.3 3.1-11 7.5C2.7 16.9 7 20 12 20s9.3-3.1 11-7.5C21.3 8.1 17 5 12 5Zm0 12.5a5 5 0 1 1 5-5 5 5 0 0 1-5 5Zm0-8a3 3 0 1 0 3 3 3 3 0 0 0-3-3Z" />
                </svg>
              </button>
            </label>
    
            <button class="btn" id="loginBtn" type="submit">
              <span class="btn-bolt" aria-hidden="true">⚡</span>
              <span class="btn-label" id="btnLabel">LOG ME IN</span>
            </button>
    
            <span class="foot foot--l" aria-hidden="true"></span>
            <span class="foot foot--r" aria-hidden="true"></span>
          </form>
        </main>
      </div>
    
      <script src="/script.js"></script>
    </body>
    
    </html>

    CSS :

    The CSS designs the login page and robot. It adds colors, fonts, borders, shadows, animations, and responsive layout. It also creates the robot’s face, hands, feet, speech bubble, and interactive effects like hovering, blinking, button animations, and form shaking.

    @import url('https://fonts.googleapis.com/css2?family=Sora:wght@500;600;700;800&display=swap');
    
    :root {
      --paper: #f4efe5;
      --ink: #23252d;
      --accent: #ff6b4b;
      --accent-deep: #e5532f;
      --teal: #2ec4b6;
      --yellow: #ffc53d;
      --shell: #fffdf8;
      --screen: #23252d;
      --eye: #fffdf8;
      --muted: #9a948a;
      --field: #faf7f0;
      --line: 2px solid var(--ink);
      --turn: .65s cubic-bezier(.5, -0.3, .25, 1.35);
    }
    
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    body {
      font-family: 'Sora', 'Segoe UI', system-ui, sans-serif;
      color: var(--ink);
    }
    
    .scene {
      min-height: 100vh;
      min-height: 100svh;
      display: grid;
      place-items: center;
      padding: 110px 24px 70px;
      overflow: clip;
      position: relative;
      background:
        radial-gradient(rgba(35, 37, 45, .07) 1.2px, transparent 1.3px) 0 0 / 24px 24px,
        var(--paper);
    }
    
    .stage {
      display: flex;
      flex-direction: column;
      align-items: center;
      position: relative;
    }
    
    /* robot */
    
    .robot {
      position: relative;
      z-index: 1;
      margin-bottom: -16px;
      animation: float 4s ease-in-out infinite alternate;
      perspective: 800px;
    }
    
    @keyframes float {
      from {
        transform: translateY(0);
      }
    
      to {
        transform: translateY(-5px);
      }
    }
    
    /* antenna */
    .antenna {
      position: absolute;
      top: -32px;
      left: 50%;
      transform: translateX(-50%);
      display: flex;
      flex-direction: column;
      align-items: center;
      z-index: 2;
    }
    
    .antenna-rod {
      width: 4px;
      height: 22px;
      background: var(--ink);
      border-radius: 2px;
    }
    
    .antenna-tip {
      width: 15px;
      height: 15px;
      border-radius: 50%;
      background: var(--accent);
      border: var(--line);
      order: -1;
      margin-bottom: -2px;
      position: relative;
      animation: bob 2.4s ease-in-out infinite;
    }
    
    .antenna-tip::after {
      content: '';
      position: absolute;
      top: 2px;
      left: 3px;
      width: 4px;
      height: 4px;
      border-radius: 50%;
      background: rgba(255, 255, 255, .85);
    }
    
    @keyframes bob {
    
      0%,
      100% {
        transform: translateY(0);
      }
    
      50% {
        transform: translateY(-2.5px);
      }
    }
    
    .robot[data-mood="excited"] .antenna-tip {
      animation-duration: .4s;
      background: var(--yellow);
    }
    
    .robot[data-mood="success"] .antenna-tip {
      background: var(--teal);
    }
    
    /* head */
    .head3d {
      width: 152px;
      height: 140px;
      perspective: 700px;
      transform-style: preserve-3d;
      transform:
        translateY(var(--hy, 0px)) scale(var(--hsc, 1)) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
      transition: transform .25s ease-out;
      will-change: transform;
    }
    
    .is-hyped .head3d {
      --hy: 5px;
      --hsc: 1.04;
    }
    
    .is-pressed .head3d {
      --hy: 9px;
      --hsc: .94;
    }
    
    /* squash on click */
    .head {
      position: relative;
      width: 100%;
      height: 100%;
      transform-style: preserve-3d;
      transition: transform var(--turn);
    }
    
    .is-turned .head {
      transform: rotateY(180deg);
    }
    
    .is-spinning .head {
      animation: victory .9s ease-in-out;
    }
    
    @keyframes victory {
      to {
        transform: rotateY(360deg);
      }
    }
    
    .ear {
      position: absolute;
      top: 48px;
      width: 16px;
      height: 40px;
      background: var(--shell);
      border: var(--line);
      border-radius: 8px;
      transform: translateZ(0);
    }
    
    .ear--l {
      left: -10px;
    }
    
    .ear--r {
      right: -10px;
    }
    
    .face {
      position: absolute;
      inset: 0;
      border-radius: 34px;
      backface-visibility: hidden;
      -webkit-backface-visibility: hidden;
      background: var(--shell);
      border: var(--line);
    }
    
    .face--front {
      box-shadow: 5px 6px 0 rgba(35, 37, 45, .16);
    }
    
    .face--back {
      box-shadow: 5px 6px 0 rgba(35, 37, 45, .16);
      transform: rotateY(180deg);
      display: grid;
      place-items: center;
    }
    
    /* face */
    .visor {
      position: absolute;
      inset: 22px 16px 20px;
      background: var(--screen);
      border-radius: 22px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 13px;
      overflow: hidden;
    }
    
    .eyes {
      display: flex;
      gap: 28px;
      transform: translate(var(--lx, 0px), var(--ly, 0px));
      transition: transform .18s ease-out;
    }
    
    .eyes.blink .eye {
      transform: scaleY(.08);
    }
    
    .eye {
      width: 19px;
      height: 25px;
      border-radius: 9px;
      background: var(--eye);
      transition: all .22s ease;
    }
    
    /* happy eyes */
    [data-mood="happy"] .eye,
    [data-mood="success"] .eye {
      width: 25px;
      height: 12px;
      background: transparent;
      border: 5px solid var(--eye);
      border-bottom: none;
      border-radius: 25px 25px 0 0;
    }
    
    [data-mood="excited"] .eye {
      transform: scale(1.2);
      border-radius: 50%;
      height: 21px;
    }
    
    /* eyes closed when the button is pressed */
    [data-mood="pressed"] .eye {
      width: 24px;
      height: 12px;
      background: transparent;
      border: 5px solid var(--eye);
      border-top: none;
      border-radius: 0 0 24px 24px;
    }
    
    .cheek {
      position: absolute;
      top: 59%;
      width: 15px;
      height: 8px;
      border-radius: 50%;
      background: var(--accent);
      opacity: 0;
      transition: opacity .3s ease;
    }
    
    .cheek--l {
      left: 15px;
    }
    
    .cheek--r {
      right: 15px;
    }
    
    [data-mood="happy"] .cheek,
    [data-mood="excited"] .cheek,
    [data-mood="pressed"] .cheek,
    [data-mood="success"] .cheek {
      opacity: .9;
    }
    
    .mouth {
      width: 15px;
      height: 5px;
      border-radius: 4px;
      background: var(--eye);
      transition: all .25s ease;
    }
    
    [data-mood="watching"] .mouth {
      width: 9px;
      height: 9px;
      border-radius: 50%;
    }
    
    [data-mood="happy"] .mouth {
      width: 30px;
      height: 12px;
      border-radius: 0 0 16px 16px;
    }
    
    [data-mood="excited"] .mouth {
      width: 22px;
      height: 16px;
      border-radius: 0 0 13px 13px;
    }
    
    [data-mood="pressed"] .mouth {
      width: 27px;
      height: 15px;
      border-radius: 0 0 14px 14px;
    }
    
    [data-mood="success"] .mouth {
      width: 38px;
      height: 17px;
      border-radius: 0 0 20px 20px;
    }
    
    /* back of the head + password meter */
    .panel {
      width: 116px;
      padding: 12px 10px 10px;
      background: var(--screen);
      border-radius: 16px;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
    }
    
    .panel-lights {
      display: flex;
      gap: 6px;
    }
    
    .panel-lights i {
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: var(--accent);
      animation: bob 1.8s ease-in-out infinite;
    }
    
    .panel-lights i:nth-child(2) {
      animation-delay: .3s;
      background: var(--yellow);
    }
    
    .panel-lights i:nth-child(3) {
      animation-delay: .6s;
      background: var(--teal);
    }
    
    .meter {
      display: flex;
      gap: 5px;
    }
    
    .meter i {
      width: 15px;
      height: 20px;
      border-radius: 4px;
      background: #3b3e49;
      transition: background .25s ease;
    }
    
    .meter[data-lvl="1"] i.on {
      background: #ff5c4d;
    }
    
    .meter[data-lvl="2"] i.on {
      background: #ff9f43;
    }
    
    .meter[data-lvl="3"] i.on {
      background: var(--yellow);
    }
    
    .meter[data-lvl="4"] i.on {
      background: var(--teal);
    }
    
    .panel-label {
      font-size: 9px;
      font-weight: 800;
      letter-spacing: 1.5px;
      max-width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      color: var(--paper);
      white-space: nowrap;
    }
    
    /* speech bubble */
    .bubble {
      position: absolute;
      bottom: calc(100% + 16px);
      left: 50%;
      transform: translateX(-50%);
      background: var(--shell);
      border: var(--line);
      color: var(--ink);
      font-size: 13px;
      font-weight: 600;
      line-height: 1.35;
      padding: 9px 14px;
      border-radius: 12px;
      width: max-content;
      max-width: 250px;
      text-align: center;
      box-shadow: 3px 3px 0 rgba(35, 37, 45, .9);
      z-index: 3;
    }
    
    .bubble::after {
      content: '';
      position: absolute;
      top: calc(100% - 5px);
      left: 50%;
      width: 10px;
      height: 10px;
      background: var(--shell);
      border-right: var(--line);
      border-bottom: var(--line);
      transform: translateX(-50%) rotate(45deg);
    }
    
    .bubble.pop {
      animation: pop .3s cubic-bezier(.34, 1.56, .64, 1);
    }
    
    @keyframes pop {
      from {
        transform: translateX(-50%) scale(.8);
      }
    
      to {
        transform: translateX(-50%) scale(1);
      }
    }
    
    /* form card */
    
    .card {
      position: relative;
      z-index: 2;
      width: min(344px, calc(100vw - 48px));
      background: linear-gradient(165deg, #fffefb 0%, #fdfaf3 45%, #f7f1e4 100%);
      border: var(--line);
      border-radius: 20px;
      padding: 36px 28px 40px;
      box-shadow: 8px 9px 0 rgba(35, 37, 45, .9);
    }
    
    .hand {
      position: absolute;
      top: -16px;
      width: 44px;
      height: 32px;
      background:
        linear-gradient(90deg, transparent 31%, rgba(35, 37, 45, .9) 32%, rgba(35, 37, 45, .9) 36%, transparent 37%, transparent 63%, rgba(35, 37, 45, .9) 64%, rgba(35, 37, 45, .9) 68%, transparent 69%) 0 12px / 100% calc(100% - 12px) no-repeat,
        var(--shell);
      border: var(--line);
      border-radius: 9px 9px 14px 14px;
      z-index: 3;
      transition: transform .25s ease;
    }
    
    .hand--l {
      left: 36px;
    }
    
    .hand--r {
      right: 36px;
    }
    
    .is-hyped~.card .hand {
      transform: translateY(-3px) scaleY(1.08);
    }
    
    .foot {
      position: absolute;
      bottom: -26px;
      width: 54px;
      height: 34px;
      background: var(--shell);
      border: var(--line);
      border-radius: 9px 9px 14px 14px;
      box-shadow: inset 0 -9px 0 rgba(35, 37, 45, .12);
      z-index: -1;
    }
    
    .foot--l {
      left: 62px;
    }
    
    .foot--r {
      right: 62px;
    }
    
    .title {
      font-size: 19px;
      font-weight: 800;
      letter-spacing: -.2px;
      text-align: center;
      margin-bottom: 24px;
    }
    
    .field {
      display: flex;
      align-items: center;
      gap: 10px;
      height: 52px;
      padding: 0 14px;
      margin-bottom: 14px;
      background: var(--field);
      border: 2px solid rgba(35, 37, 45, .22);
      border-radius: 12px;
      transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease;
      cursor: text;
    }
    
    .field:focus-within {
      border-color: var(--ink);
      box-shadow: 3px 3px 0 var(--accent);
      transform: translate(-1px, -1px);
    }
    
    .field-icon {
      width: 19px;
      height: 19px;
      fill: var(--muted);
      flex: none;
      transition: fill .18s ease;
    }
    
    .field:focus-within .field-icon {
      fill: var(--ink);
    }
    
    .field input {
      flex: 1;
      min-width: 0;
      border: none;
      outline: none;
      background: transparent;
      font: inherit;
      font-size: 14.5px;
      font-weight: 600;
      color: var(--ink);
    }
    
    .field input::placeholder {
      color: var(--muted);
      font-weight: 500;
    }
    
    .peek {
      border: none;
      background: none;
      padding: 4px;
      cursor: pointer;
      border-radius: 8px;
      display: grid;
      place-items: center;
    }
    
    .peek svg {
      width: 20px;
      height: 20px;
      fill: var(--muted);
      transition: fill .18s ease;
    }
    
    .peek:hover svg,
    .peek[aria-pressed="true"] svg {
      fill: var(--ink);
    }
    
    .peek:focus-visible {
      outline: 2px solid var(--ink);
    }
    
    /* login button */
    .btn {
      position: relative;
      width: 100%;
      height: 54px;
      margin-top: 10px;
      border: var(--line);
      border-radius: 12px;
      background: var(--accent);
      color: #fff;
      font: inherit;
      font-size: 15px;
      font-weight: 800;
      letter-spacing: 1px;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      box-shadow: 4px 5px 0 rgba(35, 37, 45, .9);
      transition: transform .18s cubic-bezier(.34, 1.56, .64, 1), box-shadow .18s ease, background .25s ease;
    }
    
    .btn:hover,
    .btn:focus-visible {
      transform: translate(-2px, -2px);
      background: var(--accent-deep);
      box-shadow: 7px 8px 0 rgba(35, 37, 45, .9);
    }
    
    .btn:active {
      transform: translate(3px, 4px);
      box-shadow: 0 0 0 rgba(35, 37, 45, .9);
    }
    
    .btn:focus-visible {
      outline: 3px solid var(--ink);
      outline-offset: 3px;
    }
    
    .btn-bolt {
      display: inline-block;
      opacity: 0;
      transform: translateX(-10px) scale(.4) rotate(-30deg);
      transition: all .3s cubic-bezier(.34, 1.56, .64, 1);
    }
    
    .btn:hover .btn-bolt,
    .btn:focus-visible .btn-bolt {
      opacity: 1;
      transform: none;
      animation: bolt-jitter .4s ease-in-out infinite;
    }
    
    @keyframes bolt-jitter {
    
      0%,
      100% {
        transform: rotate(-7deg) scale(1);
      }
    
      50% {
        transform: rotate(7deg) scale(1.2);
      }
    }
    
    .btn.is-success {
      background: var(--teal);
    }
    
    /* error shake */
    .card.shake {
      animation: shake .4s ease;
    }
    
    @keyframes shake {
    
      0%,
      100% {
        transform: translateX(0);
      }
    
      25% {
        transform: translateX(-7px);
      }
    
      50% {
        transform: translateX(6px);
      }
    
      75% {
        transform: translateX(-3px);
      }
    }
    
    /* confetti (from js) */
    .confetti {
      position: absolute;
      width: 10px;
      height: 10px;
      top: 0;
      left: 0;
      border-radius: 2px;
      pointer-events: none;
      z-index: 10;
    }
    
    /* responsive + reduced motion */
    
    @media (max-width: 560px) {
      .scene {
        padding-top: 96px;
      }
    
      .bubble {
        max-width: 210px;
        font-size: 12.5px;
      }
    }
    
    @media (prefers-reduced-motion: reduce) {
      .robot {
        animation: none;
      }
    
      .antenna-tip,
      .panel-lights i {
        animation: none;
      }
    
      .head {
        transition-duration: .01s;
      }
    
      .btn:hover .btn-bolt {
        animation: none;
      }
    
      .is-spinning .head {
        animation: none;
      }
    
      .bubble.pop {
        animation: none;
      }
    
      .eyes {
        transition: none;
      }
    }

    JavaScript:

    The JavaScript makes the page interactive. It controls the robot’s expressions, eye movement, speech bubble messages, password hiding/showing, password strength meter, form validation, button animations, blinking effect, mouse tracking, and success animation with confetti when the form is submitted successfully.

    // login robot
    const $ = (s) => document.querySelector(s);
    
    const robot = $('#robot');
    const stage = $('#stage');
    const eyes = $('#eyes');
    const bubble = $('#bubble');
    const bubbleText = $('#bubbleText');
    const meter = $('#meter');
    const meterBars = [...meter.children];
    const panelLabel = $('#panelLabel');
    const form = $('#form');
    const nameI = $('#name');
    const emailI = $('#email');
    const passI = $('#password');
    const peekBtn = $('#togglePass');
    const btn = $('#loginBtn');
    const btnLabel = $('#btnLabel');
    
    const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
    const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
    
    let done = false;
    let lastSaid = '';
    
    // helpers
    const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
    
    function setMood(mood) {
      if (!done) robot.dataset.mood = mood;
    }
    
    function say(text) {
      if (text === lastSaid) return;
      lastSaid = text;
      bubbleText.textContent = text;
      bubble.classList.remove('pop');
      void bubble.offsetWidth; // restart animation
      bubble.classList.add('pop');
    }
    
    function look(x, y) {
      eyes.style.setProperty('--lx', `${x}px`);
      eyes.style.setProperty('--ly', `${y}px`);
    }
    
    // head tilt (deg)
    const head3d = document.querySelector('.head3d');
    function tilt(ry, rx) {
      head3d.style.setProperty('--ry', `${ry}deg`);
      head3d.style.setProperty('--rx', `${rx}deg`);
    }
    
    // eyes follow the text length
    function followTyping(input) {
      const ratio = Math.min(input.value.length / 22, 1);
      look(-6 + 12 * ratio, 5);
      tilt(-5 + 10 * ratio, -8); // look down at the card
    }
    
    function turnAway(on) {
      robot.classList.toggle('is-turned', on);
    }
    
    // name
    nameI.addEventListener('focus', () => {
      turnAway(false);
      setMood('watching');
      say(pick(["A visitor. State your name.", "Typing detected. Go on, I'm watching."]));
      followTyping(nameI);
    });
    
    nameI.addEventListener('input', () => {
      followTyping(nameI);
      const v = nameI.value.trim();
      if (v.length >= 2) say(`${v}. Solid name. Filed forever.`);
      else if (v.length === 0) say("Deleted. I've already forgotten it. Mostly.");
    });
    
    // email
    emailI.addEventListener('focus', () => {
      turnAway(false);
      setMood('watching');
      say('Email next. I don\'t do spam — I don\'t even have an inbox.');
      followTyping(emailI);
    });
    
    emailI.addEventListener('input', () => {
      followTyping(emailI);
      if (EMAIL_RE.test(emailI.value.trim())) {
        setMood('happy');
        say(pick(['Now that is a proper email. Respect.', 'Valid address detected. Quietly delighted.']));
      } else {
        setMood('watching');
        if (emailI.value.includes('@')) say('Close. My sensors say: not yet.');
      }
    });
    
    // password - head turns around
    passI.addEventListener('focus', () => {
      setMood('shy');
      turnAway(true);
      look(0, 0);
      tilt(0, 0);
      say("A secret? Say no more. *turns around*");
      panelLabel.textContent = 'NOT LOOKING';
    });
    
    passI.addEventListener('blur', (e) => {
      if (e.relatedTarget === peekBtn) return; // ignore the eye toggle
      turnAway(false);
    });
    
    passI.addEventListener('input', () => {
      const v = passI.value;
      let score = 0;
      if (v.length >= 8) score++;
      if (/[a-z]/.test(v) && /[A-Z]/.test(v)) score++;
      if (/\d/.test(v)) score++;
      if (/[^a-zA-Z0-9]/.test(v)) score++;
      if (v.length > 0 && score === 0) score = 1;
    
      meter.dataset.lvl = score;
      meterBars.forEach((bar, i) => bar.classList.toggle('on', i < score));
      panelLabel.textContent = v.length === 0
        ? 'NOT LOOKING'
        : ['NOT LOOKING', 'TOO SHORT', 'GETTING THERE', 'STRONG', 'FORT KNOX'][score];
    });
    
    // show / hide password
    peekBtn.addEventListener('click', () => {
      const show = passI.type === 'password';
      passI.type = show ? 'text' : 'password';
      peekBtn.setAttribute('aria-pressed', String(show));
      peekBtn.setAttribute('aria-label', show ? 'Hide password' : 'Show password');
      if (show) say('Revealing it? Good thing I\'m facing the wall.');
      passI.focus();
    });
    
    // button hover
    function hype(on) {
      if (done) return;
      if (on && robot.classList.contains('is-pressed')) return;
      robot.classList.toggle('is-hyped', on);
      if (on) {
        turnAway(false);
        setMood('excited');
        say(pick(['Ooh. Do it. Press it.', 'This is my favorite part.']));
      } else {
        setMood('idle');
        say('The button misses you already.');
      }
    }
    btn.addEventListener('mouseenter', () => hype(true));
    btn.addEventListener('mouseleave', () => hype(false));
    btn.addEventListener('focus', () => hype(true));
    btn.addEventListener('blur', () => hype(false));
    
    // closed happy eyes on every click
    let pressTimer;
    btn.addEventListener('pointerdown', () => {
      clearTimeout(pressTimer);
      robot.classList.add('is-pressed');
      robot.dataset.mood = 'pressed';
      say(pick(['Ahh. That’s the stuff.', 'Mmm. Satisfying.', 'Beep. Do that again.']));
    });
    function releasePress() {
      clearTimeout(pressTimer);
      pressTimer = setTimeout(() => {
        robot.classList.remove('is-pressed');
        if (robot.dataset.mood === 'pressed') {
          robot.dataset.mood = done ? 'success' : 'excited';
        }
      }, 340);
    }
    btn.addEventListener('pointerup', releasePress);
    btn.addEventListener('pointercancel', releasePress);
    btn.addEventListener('pointerleave', () => {
      if (robot.classList.contains('is-pressed')) releasePress();
    });
    
    // submit
    form.addEventListener('submit', (e) => {
      e.preventDefault();
      if (done) return;
    
      const complaints = [];
      if (!nameI.value.trim()) complaints.push(["Still don't know your name.", nameI]);
      else if (!EMAIL_RE.test(emailI.value.trim())) complaints.push(['That email isn\'t a real place.', emailI]);
      else if (!passI.value) complaints.push(['A password would help.', passI]);
    
      if (complaints.length) {
        const [msg, field] = complaints[0];
        setTimeout(() => { say(msg); setMood('watching'); }, 380);
        form.classList.remove('shake');
        void form.offsetWidth;
        form.classList.add('shake');
        field.focus();
        return;
      }
    
      done = true;
      turnAway(false);
      robot.classList.remove('is-hyped');
    
      setTimeout(() => {
        robot.dataset.mood = 'success';
        say(`Access granted. Welcome, ${nameI.value.trim()}.`);
        btn.classList.add('is-success');
        btnLabel.textContent = 'ACCESS GRANTED ✓';
        look(0, 0);
        tilt(0, 0);
    
        if (!reduceMotion) {
          robot.classList.add('is-spinning');
          setTimeout(() => robot.classList.remove('is-spinning'), 950);
          confetti();
        }
      }, 420);
    
      setTimeout(reset, 5600);
    });
    
    function reset() {
      done = false;
      robot.dataset.mood = 'idle';
      btn.classList.remove('is-success');
      btnLabel.textContent = 'LOG ME IN';
      say('Again? I could do this all day.');
    }
    
    // blinking + follow the mouse
    (function blinkLoop() {
      setTimeout(() => {
        if (robot.dataset.mood !== 'success' && !robot.classList.contains('is-turned')) {
          eyes.classList.add('blink');
          setTimeout(() => eyes.classList.remove('blink'), 150);
        }
        blinkLoop();
      }, 2600 + Math.random() * 2600);
    })();
    
    let rafPending = false;
    document.addEventListener('mousemove', (e) => {
      const active = document.activeElement;
      if (done || (active && active.tagName === 'INPUT')) return;
      if (rafPending) return;
      rafPending = true;
      requestAnimationFrame(() => {
        rafPending = false;
        const rect = robot.getBoundingClientRect();
        const cx = rect.left + rect.width / 2;
        const cy = rect.top + rect.height / 2;
        const dx = Math.max(-1, Math.min(1, (e.clientX - cx) / 260));
        const dy = Math.max(-1, Math.min(1, (e.clientY - cy) / 260));
        look(dx * 7, dy * 6);
        if (!robot.classList.contains('is-turned')) tilt(dx * 12, -dy * 9);
      });
    });
    
    // confetti
    function confetti() {
      const colors = ['#ff6b4b', '#2ec4b6', '#ffc53d', '#23252d', '#fffdf8'];
      const origin = btn.getBoundingClientRect();
      const host = document.querySelector('.scene');
      const hostRect = host.getBoundingClientRect();
      const ox = origin.left - hostRect.left + origin.width / 2;
      const oy = origin.top - hostRect.top;
    
      for (let i = 0; i < 70; i++) {
        const bit = document.createElement('span');
        bit.className = 'confetti';
        bit.style.background = pick(colors);
        if (Math.random() > .5) bit.style.borderRadius = '50%';
        host.appendChild(bit);
    
        const angle = -Math.PI / 2 + (Math.random() - .5) * 1.6;
        const speed = 240 + Math.random() * 380;
        const tx = Math.cos(angle) * speed;
        const ty = Math.sin(angle) * speed;
    
        bit.animate(
          [
            { transform: `translate(${ox}px, ${oy}px) rotate(0deg) scale(1)`, opacity: 1 },
            { transform: `translate(${ox + tx}px, ${oy + ty + 320}px) rotate(${540 * (Math.random() > .5 ? 1 : -1)}deg) scale(.6)`, opacity: 0 }
          ],
          { duration: 1100 + Math.random() * 700, easing: 'cubic-bezier(.15,.6,.35,1)' }
        ).onfinish = function () { bit.remove(); };
      }
    }
    

    In this project, we built a Robot Login Form using HTML, CSS, and JavaScript. HTML provides the structure, CSS creates the robot design and smooth animations, and JavaScript adds interactive features like eye tracking, facial expressions, password hiding, form validation, and success animations. This project is a great way to practice front-end development while learning how to create engaging and user-friendly web interfaces with interactive animations. 🤖🚀

    If you run into any hiccups with your project, worry not. You can easily grab the source code for this project. Just hit the Download button to get started on your coding adventure. Happy coding!

    login form registration form signup form
    Share. Copy Link Twitter Facebook LinkedIn Email WhatsApp
    Previous ArticleHow to make Password Input Light in HTML CSS & JavaScript
    Coding Stella
    • Website

    Related Posts

    JavaScript

    How to make Password Input Light in HTML CSS & JavaScript

    1 August 2026
    JavaScript

    How to create 3D Toons Carousel Slider using HTML CSS and JS

    29 July 2026
    JavaScript

    How to create I Love You Heart Animation using HTML CSS and JS

    20 July 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
    ads
    Featured Post

    How to make Drive Mad Game in HTML CSS & JS

    30 November 2025

    How to make Animated Download Button using HTML CSS & JavaScript

    28 November 2024

    How to Get Source Code of Any Website ?

    25 January 2024

    How to make Awesome Search Bar 2 using HTML & CSS

    4 April 2025
    Latest Post

    How to make Robot Login Form in HTML CSS & JavaScript

    5 August 2026

    How to make Password Input Light in HTML CSS & JavaScript

    1 August 2026

    How to create 3D Toons Carousel Slider using HTML CSS and JS

    29 July 2026

    How to create Interactive Login Bag Form using HTML and CSS

    26 July 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.

    Ad Blocker Enabled!
    Ad Blocker Enabled!
    Looks like you're using an ad blocker. We rely on advertising to help fund our site.
    Okay! I understood