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


