How I Built a Smart Elevator Control System in Vue 3 and TypeScript

posted Originally published at thefrontendarchitect.com 3 min read

Have you ever wondered how elevator systems operate behind the scenes? I recently developed a real-time elevator control simulation using Vue 3, TypeScript, and Tailwind CSS a project that brings the complexity of multi-elevator coordination to life through a modern web interface.

In this post, I’ll walk you through the architecture, implementation details, and key lessons learned while building this interactive simulation from the ground up.

Project Overview
This simulation models a 10-floor building served by 4 independently operating elevators. Each elevator intelligently picks up passengers, navigates between floors, and drops them off at their destination all in real time with state updates every 10 seconds.

Live Demo Highlights
Four elevators running concurrently
Real-time passenger pickup & drop-off
Dynamic floor request generation
Visual floor indicators with request tracking
Scrollable, real-time activity logs
Modern, responsive user interface
Tech Stack
Frontend Framework: Vue 3 + Composition API
Language: TypeScript
Styling: Tailwind CSS
Build Tool: Vite
State Management: Vue’s built-in reactivity & composables
System Architecture
Core Data Structures
To ensure clarity and type safety, the system relies on three main TypeScript interfaces:

    src/
├── components/
│   ├── ElevatorCard.vue
│   └── elevator/
│       ├── ElevatorStatus.vue
│       ├── FloorDisplay.vue
│       ├── PassengerInfo.vue
│       └── ElevatorLogs.vue
├── composables/
│   └── useElevatorSystem.ts
├── utils/
│   └── elevatorUtils.ts
└── types/
    └── elevator.ts

Key Implementation Details

  1. Elevator Movement Logic

A basic but effective algorithm handles direction reversal and floor progression:

    function moveElevator(elevator: Elevator) {
  if (elevator.direction === 'up') {
    if (elevator.currentFloor < elevator.flors.length) {
      elevator.currentFloor++
      log(elevator, `Moved up to floor ${elevator.currentFloor}`)
    } else {
      elevator.direction = 'down'
      elevator.currentFloor--
      log(elevator, `Reached top. Reversing to down → floor ${elevator.currentFloor}`)
    }
  } else {
    if (elevator.currentFloor > 1) {
      elevator.currentFloor--
      log(elevator, `Moved down to floor ${elevator.currentFloor}`)
    } else {
      elevator.direction = 'up'
      elevator.currentFloor++
      log(elevator, `Reached bottom. Reversing to up → floor ${elevator.currentFloor}`)
    }
  }
}
  1. Passenger Pickup & Drop-Off

Passengers are generated and assigned direction-based destinations:

    function handlePickup(elevator: Elevator, floor: Floor) {
  const waitingPassengers = floor.up || floor.down ? 1 : 0
  if (waitingPassengers > 0) {
    const newPassenger: Passenger = {
      id: Date.now(),
      destinationFloor: Math.floor(Math.random() * 10) + 1,
      direction: floor.up ? 'up' : 'down'
    }

    if (floor.up) {
      while (newPassenger.destinationFloor <= elevator.currentFloor) {
        newPassenger.destinationFloor = Math.floor(Math.random() * 10) + 1
      }
    }

    elevator.passengers.push(newPassenger)
    log(elevator, `Picked up passenger going to floor ${newPassenger.destinationFloor}`)
    floor.up = false
    floor.down = false
  }
}
  1. System Controller

The main composable manages the elevator system in real time:

    function useElevatorSystem(totalFloors: number = 10, maxPassengers: number = 5) {
  const elevators = ref<Elevator[]>([])
  let moveIntervalId: ReturnType<typeof setInterval> | null = null

  function startSystem() {
    moveIntervalId = setInterval(() => {
      elevators.value.forEach(elevator => {
        dropOffPassengers(elevator)
        moveElevator(elevator)

        const currentFloorObj = elevator.flors.find(f => f.id === elevator.currentFloor)
        if (currentFloorObj && (currentFloorObj.up || currentFloorObj.down)) {
          handlePickup(elevator, currentFloorObj)
        }

        dropOffPassengers(elevator)
      })

      elevators.value.forEach(generateRandomFloorRequest)
    }, 10000)
  }

  return { elevators, initializeElevators, startSystem, stopSystem }
}

User Interface Design

Floor Display

Floor number with a circular badge

Highlighted active floor

Up/down request indicators

Clear floor labeling

Real-Time Feedback

Live updates for each elevator

Passenger count & destinations

Scrollable log with timestamps

Animated visual cues for movement

Challenges & Solutions

State Management Complexity

Managing 4 elevators with independent logic and shared global state was no small feat.

Solution: Leveraged Vue 3’s Composition API and ref/reactive to create performant, scoped reactivity.

Real-Time Synchronization

Ensuring consistent updates while keeping elevator logic independent.

Solution: I used a centralized interval loop to orchestrate operations while preserving elevator autonomy.

Type Safety

Elevators, floors, and passengers required intricate interrelations.

Solution: Strongly typed interfaces allowed safe interaction across components and composables.

Performance Highlights

Reactive efficiency via scoped updates

Efficient log storage with unshift() for quick inserts

Resource cleanup with interval teardown on unmount

Optimized rendering through component isolation

What’s Next?

The system offers exciting possibilities for further development:

Passenger Priorities: VIP or emergency overrides

Energy Efficiency: Smarter routing logic

Multi-Building Support: Shared elevator infrastructure

Analytics: Real-time performance dashboards

Interactive Mode: Manual elevator control by users

Lessons Learned

Composables = Clean architecture

TypeScript = Fewer bugs

Timing systems demand precision

Visual feedback = Better UX

Logging simplifies debugging & UX clarity

Conclusion

This project was a rewarding challenge that merged real-time systems thinking with modern frontend development. Vue 3’s reactivity, TypeScript’s type assurance, and Tailwind’s rapid styling capabilities came together to create a clean, scalable, and visually engaging simulation.

If you're passionate about algorithms, state management, or interactive web interfaces, I highly encourage exploring or extending this project.

Source Code

The full code is available on GitHub. Feel free to fork it, experiment with new features, or optimize the algorithms!

Project Links:

Live Demo: View Project

GitHub Repository: Smart-Elevator-Control-System

If you read this far, tweet to the author to show them you care. Tweet a Thanks

Really impressive work bringing elevator logic to life with Vue 3 and TypeScript! How did you find balancing real-time updates with performance, especially when managing multiple elevators simultaneously? Would love to hear if you faced any tricky challenges with state synchronization.

I didn’t face issues with state management in this project, thanks to Vue 3’s solid reactivity system combined with the Composition API. Most of the challenges were algorithmic figuring out how to combine all the functionalities and make everything work seamlessly together. The complexity wasn’t in the framework, but in architecting the logic to ensure all parts of the system interacted smoothly.

More Posts

How to apply various postprocessing effects like Bloom, Motion Blur, and Pixelation inside a Vue

Sunny - Jul 6

How to create admin panel in a minutes

IvanBorshchov - May 14

How I Started Writing Unit Tests for Vue Components

ByteMinds - Mar 29

Turn Your Vue Web App into a Mobile App (Android & iOS) in Just 5 Minutes

Toni Naumoski - Jun 23

How to set up TypeScript with Node.js and Express (2025)

Sunny - Jun 6
chevron_left