You’ve wanted to show something on your screen on several occasions, preferably something dynamic. But every time you wanted to, you had to rely on someone else making it for you.
The guide will show you how making your own overlay isn’t as daunting as the lack of tutorials would have you think.
All the BrowserSources you will ever make are basically a webpage with a transparent background that you refresh every
x seconds. That’s really it.
We’ll use a countdown as our example overlay.
- Getting started
- Overlay HTML
- Version 0.1
- Reset CSS
- Version 0.2
- Basic countdown styling
- Inserting the countdown
- Version 0.5
- Formatting the countdown
- Version 0.6
- Legal stuff
The basic idea of our countdown is that it will be in the shown in the top right corner of our stream as measured in days, hours, and minutes. Showing the seconds will be way too annoying.
Your overlay will be a local
.html file somewhere on your computer. Create one now; name it whatever.
Create a new simple scene in OBS. Then create a new BrowsersSource.
In the BrowserSource config, tick Local file and point it to the
.html file you just created. Use your monitor width and height—not your stream resolution—and set the FPS to the framerate you stream at. Be careful that scrolling with your mouse can change the values in the fields if your cursor is on them.
Check Refresh browser when scene becomes active. Otherwise your overlay will disappear when you change scenes.
BrowserSources come with this default CSS:
We want some version of this code to go in our own HTML file, so delete this entire field.
With this out of the way, finish the BrowserSource so we can move on to our HTML file. Leave OBS alone and don’t look at it until I tell you to.
I’m not going to teach you HTML, so I’ll assume a basic level of familiarity with HTML, CSS, and JS. After all, the idea is that you want to code your own overlays, right?
This is our starting HTML template:
overlay.css file in the same folder as your HTML file.
Let’s review the default CSS OBS uses for BrowserSources:
The only thing we need here is the transparent background from the first line. Let’s add this to our CSS file along with some other basic stuff:
(This assumes your monitor size is 1920×1080, of course.)
We want our HTML container to be as big as our screen, but we don’t need it to be as high, so we’re just going to use
Let’s add a placeholder text to emulate what we want:
We want it to be in the top right:
Let’s take a moment to see what this looks like in OBS:
First you’ll notice our overlay is clearly larger than 1080px, since we get a scroll bar and our countdown is cut off.
Now try changing the font size in your CSS and see what happens.
We need to refresh your overlay automatically. To achieve this, we use
<meta http-equiv="refresh" content="1"> means our page is refreshed every second. This might make it hard for you to inspect source code in your browser, so you can always set it to something higher temporarily.
This also means our page is drawn every second. The implication of this when using
1 isn’t significant, but if your page is only drawn every minute, you’ll need to remember that your browser source will take a minute to show up after you open OBS; after that, it will be refreshed every minute. Don’t assume your overlay is broken because it’s not showing up; it might just need to be drawn first.
1, because I might as well, and because constant updates to our overlay makes it easier to work with until it’s done. We’re showing seconds in the placeholder for the same reason, because I’m not really interested in showing them in a real use case.
Next, we’ll have to deal with that scroll bar which in CSS terms is called “overflow”. If we had kept the
overflow CSS rule from OBS’s template, we would just have hidden the issue instead of fixing it.
CSS has a billion quirks by default, and the simplest way to fix (most of) them is with a reset CSS. Download normalize.css and put it in
Remember to put it before your general CSS.
Now go to the settings for your BrowserSource and hit Refresh cache of current page:
That’s those two issues fixed.
You also shouldn’t have to ever use the refresh button again after this.
Basic countdown styling
First of all, our font is a mess and hard to read, so let’s fix that:
Next, we want to move the countdown just a little bit from the corner to let it breathe.
Let’s see what this looks like:
If you’re familiar with CSS and webdesign, you already know why we’re seeing the scroll bar; it’s using the wrong box sizing, which means the size of the container box increases as we add padding when it should just maintain its size while adding the padding from within.
Add this CSS to fix the issue:
Well, except that the vertical distance is larger than the horizontal one. This is because
line-height is added to the vertical padding, so let’s change our padding slightly by eyeballing:
You can perfect your padding yourself after you’ve picked your own preferred font family and size. Try
line-height: 0; for
Date object is a measure of milliseconds, we can count down to an event by subtracting the
Date of our current time from the
Date object of our future event. This will give us the number of milliseconds until the event from now.
There is one issue, however: friggin timezones. For this, we will need a library called Moment.js and its timezone library. Download them and load them in your HTML. Make sure you download either
Here is what it should look like:
You can also download the minified
.min versions of the files instead to save space, but for now you can inspect the code of them to see how they work. Same with
This is how I use the libraries to create a
To create an object for now(), you leave out the arguments:
If you don’t specify a timezone, moment.js will just use your local time which is just fine for us.
As discussed, we get our countdown in milliseconds by subtracting the latter from the former:
All we have to do now is figure out how to represent these milliseconds as days, hours, and minutes instead.
Here’s the cheatsheet to accomplish that:
"d" = diff/1000/60/60/24 "h" = diff/1000/60/60 % 24 "m" = diff/1000/60 % 60 "s" = diff/1000 % 60
Don’t copy-paste this anywhere.
%, modulus, here, but if this is too confusing for you, you can get to the numbers you want yourself.
Let’s turn this into a function that takes a number in milliseconds as argument:
I’m just leaving the seconds there in case you want to show them.
By now, this is all our code:
Right now, there’s no countdown going on so we can’t check in on OBS to see how it looks yet.
Inserting the countdown
What follows next is taking the days, hours, and minutes we’ve calculated and insert it into our HTML DOM so we literally have something to show for it.
For this, we’ll use
My preferred countdown has the format
01d 02h 03m, so this is how to represent that in HTML with
<span> elements for each counter:
We’ll include the seconds for now to make sure the countdown and overlay keep updating.
Also be sure you deleted the placeholder text:
So what have we got now:
Our countdown now is shown and updates dynamically, but each value has like a billion decimals.
Did you notice how their position keeps shifting all the time?
That’s because the font we chose isn’t monospaced. I told you to keep the seconds for now to expose issues like this.
Formatting the countdown
To keep this from happening, we need to do one of two things:
- Use a monospace font
- Create a fixed width and spacing for each
<span>element in CSS
I’m gonna stick to the first (lazy) approach:
This should fix the issue. Right?
Nope. Two other things are responsible for the numbers shifting positions:
- The number of decimals keeps changing
- The integers change between single and double digits
The first issue is fixed by rounding the values down.
The second issue is fixed by using what are called leading zeroes, as I used in my placeholder values.
Unlike our days and minutes (and seconds), our days can go beyond two digits, but because it’s the left-most value in a right-aligned line of text, it won’t shift the position of anything to the right of it with more or fewer digits. Besides, it’s going to update so rarely that it wouldn’t have been a big deal anyway.
In order to round our values and add a leading zero, I recommend you turn to
Without going into to much detail about how
d3-format works, this is how we’ll be using it:
"02d" formats to leading zero, total of two integers.
d formats integer.
Applied to our formatting function:
Let’s see where we are:
We did it!
Here is the final code, with the seconds removed:
This is the part where you create your own overlay template so you’ll be able to make another one at a later time when you’ve long forgotten 99% of this guide.
Anyway, that’s it, hope this has whetted your appetite to dig in and do your own overlays. I’d love to see your work, so please share it with me on Twitter if you don’t mind. You could also try to do something when the countdown hits zero; you probably don’t want to see something like
-00d 00h 05m.
A simple way to see if you understand the code behind this is to create a timer that counts up instead of down like this one does.
This is actually pretty important.
Do. Not. Use. Overlays. Whose. License. You. Aren’t. Sure. Of.
You do not want your stream and VODs to end up violating someone’s rights. Just because they aren’t kicking your door down with DMCAs doesn’t mean you aren’t infringing on their intelectual property.
All the more reason to make as many of the overlays on your stream as possible.
In theory, you might not even be within your rights to use this overlay. I am probably not going to issue you DMCAs, but how do you know that?
Many of you probably already use profile photos and such that are already infringing, but it’s a lot harder with overlays that you can’t remove from your VODs.
This assumes you don’t just stream ephemerally; if you don’t archive and upload your VODs, any copyright infringement is not as great a concern as any permanent VODs and uploads would be.
Here is a clip from a great panel at Twitchcon 2017 with the low-down:
Finally, another reason it’s awesome to own your own stuff is that you don’t run into problems when your overlay service decides to relaunch and shut down all overlays with a whole nine days of advance warning.