We usually create case studies about the clever things we work on, but every once in a while we create case studies about our case studies. However, the site that tells the story of our high-flying booking engine for PLAY airlines is definitely worth its own story. Our Lead Frontend Developer, Árpád, will share how he went above and beyond to make a CSS-only flight radar, cook AWS, and avoid, but not fully avoid, WordPress.
When our Aviation Business Unit Director, Richárd, approached me to help with this case study and showed me the Figma files, I instantly became very excited that I could leave my beloved monolithic application behind for a while and make something new.
At first glance, it didn’t really look like a challenge but rather a fun side project. Then, looking more deeply at the designs – created by our talented UI Designer, Gábor –, I instantly realized that there would be some tricky parts where I would scratch my head and hopelessly browse Stack Overflow for some solution.
For Icelandic startup airline PLAY, we at Mito Digital designed and developed a smooth and playful booking flow, well worthy of the brand. Curious to see how we did it? We also designed and developed a smooth and playful site where we tell you all about it. Check it out here – it’s well worth it!
The app had to work within a WordPress environment, since the site of Mito Digital is (statically generated but) WordPress-based. Without any hesitation, I knew that there was no way for me to do this using a custom WordPress template or some third-party template builder. I wanted more. I wanted to use those fancy tools that everybody was tweeting about but would become outdated in a few months. Or sooner.
So how does one fit hipster dev solutions from 2022 into a WordPress-based environment, you may ask. Well, since it’s a parallax page divided into sections, I remembered the glory days when I had to make tons of parallax sites using FullPage.js. And I was like, “So be it!” But do it with a twist!
I wanted those fancy kinds of things, but I also wanted to make everyone happy. After thinking hard about a solution where you can have your cake and eat it too, I figured that I could start small and see where I end up.
Okay, so FullPage.js with TypeScript, but how do I compile it? What will the implementation look like in WordPress?
Let’s start answering this at the end. It doesn’t matter which compiler I choose; it will eventually provide me a .js and a .css file and some other assets. So I will just put those into the WordPress page that will serve as the crib of this app, and boom! Win.
The “how do I compile it” part is more likely: with what do I compile it? Vite, of course! Remember? Rockstar tools. Zero configuration, lightning fast, widely celebrated on Twitter.
Now that we have the fundamentals, let’s see the entire timeline and talk about some interesting details.
Let me be honest. I despise all the starter kits and all the boilerplates, which claim to be lightweight and minimal, but when you take a look at the repository, you’ll go crazy seeing that mess of dotfiles and configs.
After an elegant and minimal
mkdir play-case-study && cd play-case-study && npm init -y && git init command, I was ready to launch this project to the moon and beyond.
After installing all the necessities for compiling, linting, and other micro-tasks, I began planning the structure of this project. I created an index.html file and started putting the skeleton of the site into it.
It looked something like this:
While making this, I realized that the file would become a huge mess in just a few hours since a complex site like this requires quite a bit of markup. And my time has come to add some necessary complexity to it and install my beloved Vue.
Splitting each section into a component is really a great idea when you have to deal with a lot of little widgets and other interactive elements, like on this site. Luckily, there is an implementation of FullPage.js for Vue. By using that, I was able to instantly reduce the complexity of the entry file (which was finally App.vue).
And it looked like this:
Now that all the messy stuff was hidden behind components, I was able to focus on each section independently. Not to mention the benefits of scoped styles, which really came in handy later.
The initial designs for the intro section didn’t contain any live flight feed but a huge animation. The center of it was Iceland, from where animated curves led to some of the airports where PLAY frequently flies.
I have to tell you something: I know nothing about SVG animation. Although these nice curves were screaming for one, all I wanted was to get through this as quickly as possible. Then came the help. Richárd came up with the idea of being more interactive and asked me what I thought of a real-time flight tracker instead of this “flower blooming” effect.
Well, I thought it was brilliant.
So research started for an API that would give us the current position and other metadata of the planes. Meanwhile, I was planning my implementation.
Of course, to display the flight, we needed a map. Google would be obvious, but we were on a budget. Luckily, as this wasn’t my first rodeo with maps, I knew of a great free alternative out there called Leaflet. However, out-of-the-box, it does not support custom styles. To be fancy, you need a layer provider.
💡Leaflet is merely a projector and handler of geo-coordinates and other data, while tile layers are provided by different services.
MapBox has a great toolset for customizing tile layers, so I quickly created a set for our needs. After that, I just had to configure Leaflet to use MapBox as a layer provider.
Live flight tracker
Once I finished implementing the custom map, a provider with fair prices was found. Their API looked nice indeed, but there was a problem. When we started using it, we encountered occasional performance and reliability hiccups. So to avoid the whole site hanging due to a third-party, we decided to create a proxy.
So my plan was to build a simple crawler that would call the API every n minutes, cache the response temporarily, and override it on each call. We could then build an API on top of that database.
It was obvious from space that this task required Firebase. It had cloud functions, a database, an API – you name it. That’s when the sudden idea came up in-house: “How about wasting one’s shot and planning an AWS infrastructure for this?”
Never being afraid of failing to do something new, I jumped right in. Like a real Swiss Army knife rockstar developer, I designed an infrastructure:
The recipe follows.
- 2 Lambda functions
- DynamoDB table
- 1 API Gateway
- 1 CloudWatch
Peel one of your lambda functions and connect it to the service provider API; mix it constantly. While baking, open up the other lambda and connect it to the DynamoDB table. Make sure that your lambdas have the proper rights to work with your table(s).
Once your first lambda function has been cooked, get a CloudWatch function, season it with some CRON schedule to your taste, and connect it to the first lambda. Now, all you need is an API Gateway to spice up your second lambda.
Congratulations! You’ve just created your first crawling service in AWS.
Was it this simple? Well, yes, but actually no. If you know AWS, you know how much time you can waste on giving permissions back and forth, fighting with CORS, and checking error logs. If you don’t know AWS, now you know the tip of the iceberg of troubles.
Once the AWS setup worked, we simply changed the API URL in the app, and no longer had to worry about the rate limits.
Making a radar with pure CSS
Browsing through the designs for the first time, this wonder caught my eye instantly. Not for the wow factor, but for the challenge. Of course, this radar could also be an SVG (which I still don’t know very much about when it comes to animation), but I like to push myself, so I decided it was time for some sweat and to do it in CSS only.
My logic was the following:
- I know how to draw a circle in CSS ✅
- I know how to draw a line in CSS ✅
- I know how to draw a dot in CSS ✅
- I know what the glowing part is called ❌
- I know how to draw that shape in CSS ❌
Okay, that’s three out of five. Not bad, not good.
Let’s start this from the beginning. There are four circles; this is easy: it’s two divs and pseudo-classes, and I’ll have the base. I’ll make the container fixed in size and relative, so I can place the circles in no time.
As for the glowing part, I’ll call it “handle” for now. Given that I know how to draw a line in CSS, the core of it should be easy. But how do I make it glow? Not to mention that it has to rotate. The problem is not that I don’t know how to rotate things, but rather that the center of the circles is used as the rotation origin.
What I do know is that I will place a div in the middle and start carving and poking around with it until I figure this out. I truly believe that there is some transformation magic out there that would help me transform this into the given design. But no luck at all.
As I wander in Figma, I click on the radar design, which then gives me the solution. Or at least brings me closer to it. Let me show you:
Do you see what I see? This is a pie. A quarter of a circle. And what does this mean? I will make another circle and hide 75% of it. I remembered that there is a CSS property out there that might be exactly what I need – it’s the clip-path.
What we need here are four polygonal points that clip 25% of the given element. In a generator, it looks like this:
After clipping and applying a border radius to it, I’ll finally have my pie. Cool, isn’t it? Now, I’ll just have to set a linear gradient as a background, and the glowing part of the radar is done.
The problem is, because of the clipping, I cannot put the handle line itself into the base element, so I’ll need another div for the actual handle. You might be wondering why not some pseudo-classes, but clipping is a cruel thing; it’s like a Sarlacc’s pit. It’s a no-go. Although I can’t deny that would be the ultimate, clearest solution. But instead of dreaming about what could have been, let’s see what actually happened.
So I created a new element, named it “handle”, and after some absolute positioning, I put it next to the start of our glowing part, and we were on point. After that, I only had to make it rotate – but I won’t bore you with that one.
Saying goodbye to FullPage.js
As we progressed with the site, it started to feel more like a fancy ppt file – and as we didn’t want to show some PPTs, we decided to get rid of FullPage.js. However, this came with some extra work, since one real benefit of using FullPage.js is that it automagically handles which part of the site is currently active. To achieve this by hand, I had to implement tons of IntersectionObservers. But once it slid from one section to another, the site felt more natural and smoother.
As I mentioned, this was to be presented in a WordPress environment, but with a twist. The twist, in this case, is that the mito.digital site is statically rendered. So I created a dedicated S3 bucket for the app and its assets and concealed them behind a CloudFront that only the Mito domain could access. This allows our app to be completely autonomous, as it can be deployed independently of WordPress. The only drawback is that I am unable to use dynamic imports in Vue because, when I try to load some chunks, I cannot tell the exact path of them. In other words, I cannot append the CloudFront URL to chunks while loading them. But given the size of the app, this is not a big sacrifice.
Although sometimes it seems like your hands are tied, you can still be a rockstar developer and use fancy tools within an integrated environment safely. In our case, what we won (besides all that fame) is that it’s much faster than WordPress itself. Not to mention that it has a great UX; it makes you happy as you browse it. At least, we very much hope so.
If you missed it for any reason, check out the case study site here: https://mito.digital/play
Mito Digital is a business unit of Mito, a unique powerhouse of creative & digital experts with a passion for clever things. We have been working with our clients around the globe for more than ten years, in numerous industries from aviation through lottery and retail to telecommunications. Our goal is to design and deliver human-centered and best-in-class digital solutions that meet and exceed the business goals of our clients as well as the demands of their customers.