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

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:

interface Floor {
id: number
up: boolean | null
down: boolean | null
}

interface Passenger {
id: number
destinationFloor: number
direction: 'up' | 'down'
}

interface Elevator {
id: number
currentFloor: number
direction: 'up' | 'down'
flors: Floor[]
logs: string[]
passengers: Passenger[]
nextStop: number[]
}

Component Structure

The UI is modular and cleanly organized:

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}`)
}
}
}

2. 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
}
}

3. 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:

  1. Passenger Priorities: VIP or emergency overrides
  2. Energy Efficiency: Smarter routing logic
  3. Multi-Building Support: Shared elevator infrastructure
  4. Analytics: Real-time performance dashboards
  5. 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

Share this content:

Hi, my name is Toni Naumoski, and I’m a Senior Frontend Developer with a passion for blending code and design. With years of experience as a Frontend Developer, Web Designer, and Creative Technologist, I specialize in crafting unique, responsive, and detail-oriented websites and web applications that stand out. I bring deep expertise in HTML, CSS, and JavaScript working fluently with modern frameworks like React, Angular, and Vue, as well as animation libraries like GSAP. My creative side thrives in Photoshop and Figma, and I enjoy extending functionality using tools like Express.js and ChatGPT. My work is guided by high integrity, strong communication, a positive attitude, and a commitment to being a reliable collaborator. I take pride in delivering high-quality digital experiences that are both technically solid and visually compelling.