DEV Community

UmapathiChandrasekaran
UmapathiChandrasekaran

Posted on

How I Built a Cinematic Toothless Login Portal with Angular 21 🐉

Have you ever wanted to build something so fun that you
forgot you were even coding? That's exactly what happened
when I built this — a fully cinematic, interactive login
portal featuring Toothless the Night Fury from
How to Train Your Dragon 🐉

🔗 Live Demo

👉 Try it here

💻 View Source on GitHub


✨ What Does It Do?

This isn't just a login form. Toothless reacts to everything you do:

  • 👀 Eye Tracking — the dragon's pupils follow your cursor in real time as you move around the screen
  • 🪽 Shy Behavior — when you click the password field, Toothless lowers his wings and hides shyly
  • Plasma Charge — hitting the login button triggers a full plasma charging animation sequence
  • 🌩️ Cinematic Thunder — custom lightning and thunder effects fire during dramatic moments

🛠️ Tech Stack

  • Angular 21 — component architecture and reactive form state handling
  • Tailwind CSS v3 — all layout and utility styles
  • Pure SVG — Toothless is hand-crafted SVG, no images or libraries
  • CSS Keyframe Animations — all motion is pure CSS
  • Gemini AI — used to engineer the cinematic animation sequences and thunder/lightning effects

💡 How the Eye Tracking Works

The core idea is simple — track the mouse position
relative to the eye center and move the pupils:

@HostListener('mousemove', ['$event'])
onMouseMove(event: MouseEvent) {
  const eyeRect = this.eyeElement.getBoundingClientRect();
  const eyeCenterX = eyeRect.left + eyeRect.width / 2;
  const eyeCenterY = eyeRect.top + eyeRect.height / 2;

  const angle = Math.atan2(
    event.clientY - eyeCenterY,
    event.clientX - eyeCenterX
  );

  const distance = 4; // max pupil travel distance
  this.pupilX = Math.cos(angle) * distance;
  this.pupilY = Math.sin(angle) * distance;
}
Enter fullscreen mode Exit fullscreen mode

The pupils are constrained to a small radius so they
never go outside the eye boundary — giving a natural
realistic feel.


🪽 How the Shy Behavior Works

When the password field receives focus, Angular's
reactive form detects the state change and triggers
a CSS class that animates the wings downward:

onPasswordFocus() {
  this.isPasswordFocused = true; // wings lower
}

onPasswordBlur() {
  this.isPasswordFocused = false; // wings rise back
}
Enter fullscreen mode Exit fullscreen mode

In the template:

<div [class.wings-down]="isPasswordFocused" 
     class="toothless-wings">
</div>
Enter fullscreen mode Exit fullscreen mode

⚡ The Plasma Charge Sequence

On form submission, a multi-stage animation fires:

  1. Toothless opens his mouth
  2. A glowing plasma orb builds up
  3. The orb pulses and expands
  4. A flash covers the screen
  5. Login success state appears

This entire sequence is timed using Angular's
setTimeout chain synced with CSS animation durations.

Top comments (0)