Most of the animations I’ve been working on have been put to immediate use on the broadcasting side of my live streaming efforts. These are the interstitial screen animations, the stingers, and the occasional “flare” widgets. The “holy grail” then are the animations used for alerts, which take a bit more know-how to get working, and which need to be applied through third-party services like Streamlabs.

Events in Livestreaming

Events during a stream are usually triggered by the actions of a viewer. There’s generally only a handful, and are platform dependent: a new follower, a subscription or renewal, a donation, a “raid”, or a host. For the new or most basic streamer, these events are never noticed unless the streamer has a dashboard on another monitor to keep an eye on things because the major streaming platforms don’t have a means of surfacing these events to other viewers, which is something I’m kind of amazed at. Instead, we have to rely on a third party integration to handle this kind of thing.

Handling Events With Streamlabs

Streamlabs is one of the heavy hitters in third-party integration. By purposefully connecting your streaming account to their service, they can get info from the platform’s API which allows them to hook into the event stream. When a viewer takes an event-raising action, Streamlabs will pick up on it and trigger a visual alert that all viewers can see.

An alert is defined by a few settings. They can be enabled or disabled (although the platform will still broadcast them, disabling them at the partner level will prevent them from being available to the streamer for integration), the layout and simple animation can be set, the text and font and style can be set, and the streamer can mix things up by setting up variations of alerts to show in response to a specific event.

In order to display the event to other users, streamers have to include the third-party-provided widget as a source within their streaming software. This usually takes the form of a webpage source. When an event is triggered, Streamlabs will trigger the event display at the URL they provide, and when set as a source in XSplit of OBS, the resulting alert will display on the live stream for everyone to see.

Advanced Animations

Although Streamlabs has a decent stable of stock animations that streamers can use, the discerning broadcaster will want to provide their own. There are several services out there which can provide packages of alert animations and overlay elements for use with Streamlabs and other third-party players, but we’re going to look at the technical steps needed to integrate a custom animation with Streamlabs.

Because Streamlabs procs their alerts via web code, a custom animation requires some knowledge of HTML, CSS, and Javascript. At the bottom of the Alert Box section of the Streamlabs dashboard, there’s the option to Enable Custom HTML/CSS. This will allow users to enter their own code that interacts with the events, and which interacts with custom animations that can be uploaded and associated with individual events.


The core of the alert system is the token. A token is a known string that the system will look for in your HTML code. This token is replaced with values from the event, such as the name of a user who follows you, or the number of people whose channels are hosting yours. Without the tokens, the event will proc, but there will not be any user-specific information. For example, to display the name of the user responsible for the event, use the “{name}” token. To display the image or video associated with the event, use “{image}”.

How you organize your HTML is really up to you. The default code associated with the alert is tied into Streamlabs internal CSS and Javascript, and while it shouldn’t interfere with custom code, you can remove their default HTML and replace it with your own.

At the bare minimum, the code above will display our animation and the name of the user who triggered the event (in this case, a follow). The “<video>” tag is an HTML5 standard which tells the browser that the contents — in this case, whatever will replace “{image}” — should be handled as a video, complete with video controls (which we won’t see). The WEBM format is preferred; it’s a lightweight wrapper designed for web and mobile use. I’ve had to download a third party encoder for Adobe Media Encoder in order to be able to export to WEBM, since it’s not quite as ubiquitous as it should be in this day and age.

The <div> with the ID “content” contains containers for the name of the user who triggered the event, but there’s some structure here that allows my alerts to provide some additional animation not supported by the stock Streamlabs behaviors. The “slname” container will accept the name of the user but hides it from the display. Later, we’ll show the Javascript that takes the contents of that container, animates it, and puts it into the container “name”, which does display.

Styling the Output

Styling with CSS is most certainly an art — an art at which I suck — but it’s crucial to ensure that all of the elements on the page end up where they are meant to be. The good news is that unlike a standard webpage viewed in a browser, we don’t have to worry much about the user — you, the streamer — resizing the window and messing up the layout, so we can work with absolutes and not worry about eventualities. As with CSS in general, we start out broad and narrow our focus as we go.

First, we need to style the “alert” container as a whole. Here, we’re setting it to 1920×1080 pixels, which is the width and height of a 16:9 1080p display Depending on the resolution that you stream, this might need to be adjusted to 720p dimensions, but the key is that this “alert” container will take up your entire viewport. Don’t worry: Streamlabs broadcasts a transparent background by default. The “position” attribute allows the “alert” element to be positioned exactly as we specify, and “opacity” makes the alert visible.

Next, we have the “video” element. The size of this is set to the dimensions of our encoded animation, which in this example is 357×150. Again, we set the position to absolute so it stays where we put it. The weird part is the “left” and “margin-left”. This is one of those “stupid style tricks” that designers like to use; by setting the left edge of this “video” element to 50% and then setting the margin to an explicit 1/2 value of 357px, this effectively centers the video inside the container “alert” regardless of how wide the “alert” container is. The good news is that this removes the need to micromanage the placement of the video element; the bad news is that I find this kind of mathematical gymnastics really stupid. Effective, but stupid.

The “content” style is basically the same as the “video” style because we’re going to overlay the “name” of the user over the video. Inside of “content”, we have “name”, and this is the one we have to fudge the most because as we have the video exactly where we want it, we need to ensure that the resulting name of the user who fired the event is placed properly. We set the width and height to match the “video” and “content” containers, align the text in the center, and then use padding, top, margin, and font-size to get the resulting “name” value into the center of our alert video…theoretically. It’s really a trial and error thing to get the best placement, but later we’ll see that because I wanted the text animated, all of this gets blown out of the water.

Javascript for Control

Javascript is a parsed language that runs at the browser (aka “client-side”) which makes it almost universally available for anything webbish. Using a framework like jQuery, we can address the HTML elements by type, ID, or even CSS value. In addition, we’re using two other libraries: TypeFill and TweenMax.

We start by loading three scripts: jQuery, TextFill, and TweenMax. We have to make sure these are loaded because otherwise, our further operations will throw errors, so we set a flag, and if that flag is set to TRUE, we call the “playAnim()” method.

“playAnim()” finds the “video” element and adds a “listener”. Javascript has its own set of events, one of which is an “onLoad” for rich content like video. When the video has loaded completely, this “onLoad” event is fired and we call the “animate()” method which handles the actual activity of the alert.

Animate handles the bulk of the action. First, we set some values which will control the animation of our text, like speed and the delay between animation “frames”. Next, we use TweenMax to take action in sequence: first, display the “alert” container, and once it’s complete, call “playVid”. Then, we call a method called “typeEffect” which we use for the name animation. After 5 seconds of display, we will fade the “alert” container out over one second, ending the display of the alert.

“playVid” uses the native HTML5 commands to identify the “video” container, and then to “play” the video.

“typeEffect” reads the contents of the “slname” container (the hidden container which contains the “{name}” token that will be replaced by Streamlabs with the name of the user) and over a few “ticks” — an internal metronome that we can use for tracking progress over time — we split the user’s name by letter, and one by one, add the letters to the displayed “name” container. This little bit of code results in a “typewriter effect” for the username display. It’s not quite the same as the animation I use in the alert video, but it’s as close as I can get in pure Javascript, and is acceptable to me.

Problems With Names

Testing using my name “Scopique” seems to look pretty good. But what if someone named “TwitchUserAccount177b” follows my channel? The length of that name is going to exceed the confines of the video because we’re not actually constraining the text within the video…we’re only using the permissive CSS rules to vaguely define the bounds of where we want the text to be contained. We could use overflow control to wrap or even hide anything that pushes beyond the bounds, but that’s kinda dumb in this case. Instead, we use a library called TextFill.

TextFill takes the contents of a container and compares the font-size to the size of the container. Style wonks will be quick to point out that there’s no real way to compare the two because fonts can’t be accurately measured with certainty — and that’s a big problem. Instead, this library constantly resizes the font and compares the reported width of the container (a hidden “<span>”) to the specified parent or hardcoded width. If the reported width exceeds that value, the font is scaled down. When we call this function every time we add a letter through the typewriter effect, the font appears to shrink as we build so that the entire name can fit within the bounds of the video frame.

The problem, though, is that this messes up the spacing of the resulting name. “Scopique” works well because it’s what I used to calibrate the placement of the content of “name”. While centering the text is OK, longer names have difficulty centering vertically. I haven’t yet found a way to counter this, nor have I found a way to get the text to not move around when resizing. Ultimately I don’t think either will be possible, at least not without modification of the core library.


Streamlabs doesn’t treat video any different from a still image uploaded as an alert except that it’s up to the user to trigger the start of the video. Using an animated GIF version of the animation would work better, really, without the need for the video-specific Javascript, assuming the timing could be controlled so that the animation of the text fires when appropriate. Using a GIF would put the control and design squarely within the realm of Streamlab’s native tools, and wouldn’t require the use of custom HTML, CSS, or Javascript at all.

Consequently, maybe having a fixed bordered animation isn’t the best option. With left and right borders, the behavior of the text is pretty obvious because I had to find ways to cram any length of text into a visually calculated space. If the animation were to feature a container that made the left and right borders more…vague…then the dynamic sizing of the text wouldn’t be so critical.

Ultimately, it’s still going to come down to using CSS to position text in relation to the animation, which is rather grey-box to me — I’m a developer by trade, a designer by necessity, so style isn’t really my forte. The good thing about this setup is that once the source has been referenced in XSplit or OBS, it can be resized and moved around the screen if it’s smaller than the broadcast resolution. That provides some extra leeway in the design of the alert.


Owner and author.

Leave a Reply

Your email address will not be published. Required fields are marked *