English
Note

Full Source Code > The complete standalone index.html used in this overlay is available here: > https://gist.github.com/MarsuvesVex/51bc48490ca9e7700994e5ba16cde50b

This post documents the original HTML-based lower-third overlay used in OBS before it was migrated into a Next.js-powered overlay system.

The goal was simple:

  • Predictable sizing in OBS
  • Zero layout shift
  • Smooth, readable animation
  • Fully self-contained (HTML + CSS + JS)

Overview

The lower-third consists of four visual layers:

  1. Icon block (fixed 90×90)
  2. Animated bar (top + bottom border only)
  3. Primary title text
  4. Secondary subtitle text

All animation timing is orchestrated via GSAP TimelineMax, allowing the entire sequence to be played forward and reversed cleanly.

Scroller

The end result looking something like this:

Scroller

Font Handling

The overlay uses Oswald, loaded directly from Google Fonts:

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Oswald" />

Using a hosted font avoids system font inconsistencies across OBS machines.

Note

OBS caches browser sources aggressively. Always hard-refresh or change the URL when testing font changes.


Layout Structure

At a high level:

<div class="title">
  <div class="icon-holder"><img /></div>
  <h2>Title</h2>
  <h3>Subtitle</h3>
  <div class="title-inner"></div>
</div>

Key constraints:

  • .title has a fixed width (700px)
  • .icon-holder never affects layout flow
  • Text is absolutely positioned to prevent reflow

CSS Breakdown

Global Reset

html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  background: transparent;
  overflow: hidden;
}

This ensures OBS sees only the overlay itself.


Icon Holder

.icon-holder {
  position: absolute;
  width: 90px;
  height: 90px;
  transform: scale(0);
  bottom: -10px;
}

The icon starts hidden and is scaled + rotated in.


Title Text

.title h2,
.title h3 {
  opacity: 0;
  transform: translateX(-20px);
}

Text is animated after the bar finishes expanding to avoid jitter.

A subtle drop shadow improves readability on bright backgrounds.


Animated Bar

.title-inner {
  width: 0vw;
  height: 90px;
  border-top: 3px solid #7289da;
  border-bottom: 3px solid #7289da;
  position: absolute;
  left: 90px;
}

Only the top and bottom borders are drawn. Left/right borders were intentionally removed to avoid boxing the content.


Animation Timeline

GSAP controls the entire lifecycle:

  1. Icon scales + rotates in
  2. Bar expands horizontally
  3. Text fades and slides in
  4. Hold duration
  5. Text fades out
  6. Bar collapses
  7. Entire animation reverses

Timeline Setup

var tl = new TimelineMax({
  repeat: 0,
  onComplete: reverseFunction,
});

The timeline is played forward, then reversed to guarantee symmetry.


Icon Animation

tl.to(iconHolder, 1.2, {
  scale: 1,
  rotation: -180,
  ease: Power1.easeInOut,
});

The counter-rotation on the image keeps it visually upright.


Bar Expansion

tl.to(title, 2.5, {
  width: 700,
  ease: Power1.easeInOut,
});

The width matches the .title container exactly to avoid subpixel drift.


Text Reveal

tl.to(h2, 0.35, { opacity: 1, x: 0 });
tl.to(h3, 0.35, { opacity: 1, x: 0 });

Text is intentionally fast to keep the overlay feeling responsive.


Triggering in OBS

The animation is restarted every 20 seconds:

setInterval(function () {
  tl.restart();
}, 20000);

This was later replaced with cooldown-based logic in the Next.js version.


Why This Version Still Matters

Even though the overlay is now implemented in Next.js:

  • This HTML version is portable
  • It works in any OBS browser source
  • It is easy to prototype and tweak

Most of the timing, spacing, and animation principles carried directly into the React implementation.


Next Evolution

The modern version adds:

  • JSON-driven playlists
  • Cooldowns
  • Querystring overrides
  • Debug overlays
  • Font loading via next/font

But the foundation started here.

0
0
0
0