Join the weekly newsletter
By Arturo Cuya
@arturo__cuyaImagine yourself as your TV user. You download a new and shiny app that you’re sure will get you out of the routine.
You open it and… you wait.
Two.. Five… Ten seconds even. Watching a logo, a wheel, and an empty background.
You’re then bored to your soul and hit the home button, thinking: Where’s my phone again? Time for some TikTok.
The most catastrophic engagement metric — the one we want to keep as low as possible — is the bounce rate, i.e., when a user leaves the app without even trying it.
And the #1 feature that is promoting bounces in your app is showing a boring spinner.
This spinner is so boring it’s probably called “Bob” or something.
But there’s a reason why we’re showing this, right? We simply need time to load initial resources! Because it is true that worse than a spinner would be showing a skeleton of an app.
That would look just… broken.
Well, good news: Today I’ll show you, in four simple steps, there is a smarter way to show our users some placeholder content while we load the resources needed to really start the experience we want to provide.
Netflix is probably one of the best-engineered applications out there. And they are definitely the best at solving this problem.
What do they do? They show the user a short 3-4 second video with their nicely animated logo. This is called a splash video.
IDK about you guys, but hearing that “Tu-Thummm” always gets me to the right mental space to… rot into my couch.
We already have splash screens in Roku, but those just cover the time it takes the device to load our application into memory. A splash video is meant to be shown after the native splash disappears.
It is true that just the task of producing a whole video with a nice animation is a costly project that a small team might not be able to afford. Plus, there are a lot of edge cases to consider to keep that initial experience in sync with what’s supposed to happen in the background.
Still, a splash video at the start of your application adds tremendous value to your app’s experience (especially for first-time users), and it’s a smarter way to load resources without boring your users.
So, how do you implement one? I’ll explain this to you in four steps, where my goal is to streamline this process in a simple and organized way. With so many things happening asynchronously, we want to ensure that the final code is easy to follow from top to bottom.
Let’s get started.
Video production is not my area of expertise, so I won’t go into much depth for this. But let me give you some advice as a user instead of an engineer:
Finally, according to the Roku documentation for supported video formats and my video encoding expert (ChatGPT), the best format and encoding for this asset is:
An MP4 container with AVC (H.264) video codec and AAC audio codec.
We want to keep the video lightweight since we’ll need to include it in our build for blazingly-fast™ load times.
The native Roku splash image is the one defined in your manifest, with the following entries:
splash_screen_sd=pkg:/images/splash_sd.png
splash_screen_hd=pkg:/images/splash_hd.png
Roku automatically shows the native splash while the app binary is being compiled and loaded into memory, so you don’t need to worry about code changes at this point.
Also, this might be a good time to rethink the content of that splash image too. It will need to match 1:1 with the first frame of the video, so keep that in mind.
What should we show after the native splash image? Another splash image, of course! See, we still need time to prepare the video node and our background tasks.
Here’s what you need to do for this step:
First, load a Poster
node with the same image that is set in your manifest for the splash screen. Remember to set the loadWidth
and loadHeight
fields before setting the uri
field to make sure the image scales properly. If you need to programmatically decide what image to load based on the device’s resolution, you can use roDeviceInfo
’s GetUIResolution.
After the image is loadStatus = "ready"
, load a Video
node below the image and set its content to a single MP4 video for our splash screen. Some things to consider:
enableUI
and enableTrickPlay
fields of the Video node.Finally, this is also a good moment to start any background tasks for data fetching. I recommend you handle resolving them through a Promise, so that you can use promise.all([...])
to handle their fulfillment with a single handler function.
After you have your Video
node ready and all your background tasks have started, it’s time to start the Splash Video. The main idea is to fade out the splash image with a nice animation to reveal the video underneath.
One thing that I recommend here is that you wait for the video to be in state = "playing"
before fading out the image on top.
This is to avoid any unexpected quirks from the Roku player where the video might be blank while the MP4 is being loaded into memory, or any unexpected buffering states.
Consider using the Video
node field asyncStopSemantics = true
to avoid blocking the render thread when the video ends. That has been an annoying cause of crashes in Roku OS 12.5.
The Video
node field that will tell you that your splash screen has ended is state = "finished"
. But remember that you also need to wait for your background tasks to finish executing, and for your next screen to finish rendering.
Again, I recommend handling these parallel tasks through the use of Promises.
If by the time the Splash Video has finished your background tasks are still running… Bad news, we’ll need to show a spinner :(. Hopefully for a minimal amount of time since the tasks should be close to being finished.
Show your splash image again (or another one that matches with the last frame of the video), and consider waiting for at least 1 second before showing the spinner. We humans get impatient when we see loading states, maybe that one second is enough for everything else to finish.
When your tasks are done and the next screen is rendered, remove the Video
node instance, make the next screen visible, and give it focus.
That’s it!
There’s one caveat here, if the next screen contains a video you won’t be able to preload it since on the Roku platform only allows for one video to be instanced at any time.
For absolute beginners, this course is meant to set you in the right path to make use of modern tools and best practices from day one. Subscribe to the newsletter to get notified when it's available.
Use these tools to 10x your workflows. Free and open source forever.