OBS Scrolling Lower‑Third Overlay
A built‑in Next.js + OBS Browser Source overlay for Mars Chat that displays rotating promotional lower‑thirds (Discord, YouTube, etc.) with cooldowns, animations, and debug tooling.
This overlay is designed to be:
- OBS‑safe (no layout thrash, no pointer interaction)
- Config‑driven (JSON now, DB later)
- Deterministic (cooldowns persisted across reloads)
- Extensible (multiple items, rotation, future admin UI)
Overview
The overlay renders a single animated item at a time (“lower third”) and rotates through a configured list.
Each item:
- Animates in from a direction
- Holds on screen for a duration
- Animates out
- Enters a global cooldown before it can be shown again
The overlay is embedded in OBS via a Browser Source pointed at a Next.js route.
Route
/obsoverlays/scrollerRecommended OBS settings:
- Width:
1920 - Height:
1080 - Custom CSS: none
- Shutdown source when not visible: ❌
- Refresh browser when scene becomes active: ❌
Configuration (JSON)
For now, items are loaded from a static JSON file.
{
"items": [
{
"id": "discord",
"iconUrl": "https://cdn.prod.website-files.com/.../icon_clyde_blurple_RGB.png",
"title": "Join my Discord",
"subtitle": "!discord to join – All things fun",
"holdMs": 5500,
"position": "bottom-right",
"direction": "from-right"
},
{
"id": "youtube",
"iconUrl": "/images/youtube.png",
"title": "Subscribe on YouTube",
"subtitle": "New uploads weekly",
"holdMs": 2500,
"position": "bottom-right",
"direction": "from-right"
}
]
}Item Fields
| Field | Description |
|---|---|
id | Stable identifier (used for rotation + cooldown keys) |
iconUrl | Icon image (transparent PNG recommended) |
title | Primary text |
subtitle | Secondary text |
holdMs | Time visible before animating out |
position | bottom-left, bottom-right, top-left, top-right |
direction | from-left, from-right, from-top, from-bottom |
Rotation Logic
- Items rotate sequentially
- One item renders per page load cycle
- Index is maintained in memory
- Cooldown is enforced globally
Rotation order:
item[0] → item[1] → item[2] → … → loopCooldown
A global cooldown prevents the overlay from firing too frequently.
- Default: 30 minutes
- Stored in
localStorage - Survives OBS refreshes and scene switches
Key format:
obs:overlay:lastFireCooldown Rules
- If cooldown is active → overlay does not animate
- If cooldown expired → next item animates
force=1bypasses cooldown (debug/testing only)
Query Parameters
debug=1
Enables on‑screen diagnostics.
- Draws a faint bounding box
- Shows live state text
- Enables structured console logging
Example:
/obsoverlays/scroller?debug=1force=1
Bypasses cooldown.
/obsoverlays/scroller?force=1Can be combined:
/obsoverlays/scroller?debug=1&force=1Debug Overlay
When debug=1 is present, the overlay shows:
- Current item ID
- Animation phase
- Rotation index
- Cooldown timestamps
- Frequency values
This is non‑interactive and OBS‑safe.
Fonts
Fonts are loaded using Next.js next/font (not Google CSS).
- Ensures deterministic rendering in OBS
- Avoids CORS and preload issues
- Prevents font flash on reload
The overlay uses the Oswald font family.
Animation
- GSAP‑based
- No layout reflow during animation
- Transform‑only (GPU friendly)
Animation phases:
hidden → slide in → hold → slide out → idleFuture Work
Planned upgrades:
- Admin UI for managing items
- Per‑item cooldowns
- Priority / weighting
- Time‑based schedules
- Twitch / YouTube event‑driven triggers
- Live preview inside admin panel
Design Constraints (Intentional)
- No timers when idle
- No pointer events
- No server state required
- Safe for OBS browser caching
- Deterministic behavior
This overlay is meant to be boring, predictable, and stream‑safe.
TL;DR
- Next.js route → OBS Browser Source
- JSON‑driven rotating lower‑thirds
- 30‑minute global cooldown
- Debug mode for layout + state
- Admin‑ready architecture