Starting Soon Screen OBS [2026]: 11 Steps in 25 Min
![Starting Soon Screen OBS [2026]: 11 Steps in 25 Min](https://ivipid.com/blog/wp-content/uploads/2026/10/how-to-make-a-starting-soon-screen-2026-gen-1024x585.webp)
What you need before you start (prerequisites with versions) · Plan the screen and set up the project (Step 1) · Build the looping background with FFmpeg (Step 2) · Create the scene and add the background (Step 3) · Add the logo and text lines (Steps 4 and 5) · Build the countdown as a browser source (Step 6) · Add music and set the audio levels (Step 8) · Switch to the live scene automatically with Lua (Step 9) · Make a stinger transition with an alpha channel (Step 10) · Test the screen for Twitch and YouTube (Step 11) · The complete working project · Common pitfalls · Troubleshooting · Advanced tips · Questions creators ask
A starting soon screen is the stretch of video your audience sees before you appear on camera. This tutorial builds one in OBS Studio 33.0.1, the stable release that landed on October 29, 2026, and the result works the same on Twitch and YouTube because OBS sends whichever scene is live. You build it once, then reuse it for every stream.
You do not need a paid plugin or a designer. OBS Studio is free, open-source software by the project’s own description, and the community keeps adding extras to the OBS forums resource section, such as an audio waves visualizer. The kit below uses only built-in sources plus FFmpeg for two small media files.
By the end you will have a looping 10-second background, a logo, a countdown that runs from a browser source, a music bed, a script that flips to your live scene on a timer, and a one-second stinger transition. Budget about 25 minutes for the whole starting soon screen if your assets are ready. If you are collecting more ideas for stream intros and overlays, that hub lists the rest of the series.
What you need before you start (prerequisites with versions)
OBS 33 also changes a few things that touch this tutorial. The browser source and browser docks run on a much newer embedded Chromium framework, which the release notes describe as a massive update covering the period from the July 2024 release to September 2026. Reportedly the engine jumped from version 127 to version 150. Old HTML overlays usually still work, but you should test them, and we do that in Step 6. Third-party plugins keep loading from the legacy locations until OBS Studio 34.0. Linux users take note: the official package now targets Ubuntu 26.04, and Ubuntu 24.04 support was removed.
| Requirement | Version or spec | Why you need it |
|---|---|---|
| OBS Studio | 33.0.1 (October 29, 2026) | Scenes, sources, transitions, scripting, streaming |
| macOS (if on Mac) | 13.0 or newer | Minimum listed on the OBS site |
| Linux (if on Linux) | Ubuntu 26.04 for the official package | Ubuntu 24.04 support was removed in OBS 33 |
| FFmpeg | A current stable build with libx264 and libvpx-vp9 | Builds the loop and the stinger |
| Python 3 | Any current 3.x release | Optional countdown file writer (Step 7) |
| Text editor | Any plain-text editor | Edits the HTML countdown and Lua script |
| Logo | PNG with transparent background | Brand mark on the screen |
| Music | A track you hold the licence to stream | Audio bed under the countdown |
Check your FFmpeg install now. Run the two commands below. If the first prints a version and the second finds both encoders, you are set.
ffmpeg -version | head -n 1
ffmpeg -encoders 2>/dev/null | grep -E "libx264|libvpx-vp9"
On Windows, swap head -n 1 for findstr ffmpeg and the grep for findstr as well. Any build that lists both encoders works. If libvpx-vp9 is missing, you can still finish everything except the alpha WebM stinger in Step 10, and that step has a ProRes fallback.
Plan the screen and set up the project (Step 1)
A good starting soon screen answers four questions in about two seconds: who is this, what is happening, when does it start, and is my audio working? Everything else is decoration. Plan for five elements: a moving background, your logo, a line of text, a countdown, and a quiet music bed. Add more and viewers stop reading any of it.
Pick your render settings before you make a single asset, because changing resolution halfway through means redoing everything. Use 1920×1080 at 30 frames per second for the screen itself. A static or slow-moving scene gains nothing from 60 fps, and a 10-second loop at 30 fps is exactly 300 frames, which keeps the loop math in Step 2 clean. Your live scene can run at whatever frame rate your game needs, since the canvas output rate is what counts.
Render settings
| Asset | Resolution | Frame rate | Length | Export format |
|---|---|---|---|---|
| Background loop | 1920×1080 | 30 fps | 10 s (300 frames) | MP4, H.264, no audio track |
| Logo | Up to 800×800 | Still | Not applicable | PNG with transparency |
| Countdown | 1920×300 browser source | Runs live in HTML | Set by you (5 min default) | HTML file |
| Music bed | Not applicable | Not applicable | 3 min, looped | WAV |
| Stinger | 1920×1080 | 30 fps | 1 s (30 frames) | WebM VP9 with alpha |
| Test recording | 1920×1080 | 30 fps | 30 s | MKV, local file |
These values are working choices for this build, not platform rules. Twitch and YouTube publish their own encoder guidance, and Step 11 tells you where to read it.
| Step | Task | Minutes |
|---|---|---|
| 1 | Folder, canvas, settings | 2 |
| 2 | Render the looping background | 3 |
| 3 | Scene and background source | 2 |
| 4 and 5 | Logo and text lines | 3 |
| 6 | Browser countdown | 3 |
| 7 | Text-file fallback | 2 |
| 8 | Music bed and levels | 2 |
| 9 | Auto-switch script | 2 |
| 10 | Stinger transition | 3 |
| 11 | Test recording and go-live check | 3 |
That adds up to 25 minutes when the logo, background image, music and stinger frames already exist. Now create the folder. A single project directory keeps every path in one place, which saves you when you move to a new PC.
mkdir -p starting-soon-kit/{assets,build,scripts,html}
cd starting-soon-kit
cp ~/Downloads/logo.png assets/logo.png
cp ~/Downloads/background.png assets/background.png
cp ~/Downloads/music.wav assets/music.wav
ls assets
Then open OBS and go to Settings, then Video. Set Base (Canvas) Resolution to 1920×1080 and Output (Scaled) Resolution to 1920×1080 as well, and choose 30 from the common FPS values for now. If your upload speed forces a lower stream resolution, you can scale down here later without touching the scene. Click Apply. Setting the canvas first matters because every source you add snaps and scales relative to it.
What you get on the free plan: all of it. OBS has no watermark, no length limit and no export cap, so the only costs in this project are your own assets and your music licence.
Build the looping background with FFmpeg (Step 2)
A still image works as a background, but a gentle motion loop tells viewers the stream is alive and not frozen. The trick is to make the loop mathematically exact so there is no visible jump at the seam. A slow zoom that follows a sine wave does that: the zoom starts and ends at the same value, so frame 300 hands off cleanly to frame 1.
Start with a background image at least 1920×1080. Upscale it to 3840×2160 first so the zoom has pixels to work with, otherwise the motion looks soft. The command below makes a 10-second clip at 30 fps and strips audio.
ffmpeg -y -loop 1 -framerate 30 -t 10 -i assets/background.png \
-vf "scale=3840:2160,zoompan=z='1.06+0.05*sin(2*PI*on/300)':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=1:s=1920x1080:fps=30,format=yuv420p" \
-c:v libx264 -crf 18 -preset slow -an -movflags +faststart \
build/background_loop.mp4
Read the zoom expression once, because you will tweak it. The value 1.06 is the center zoom, 0.05 is how far it swings either side, and 300 is the frame count of the loop. Change the clip length and you must change that 300 to match (length in seconds times 30). The sine of a full circle returns to zero, so the first and last frames match.
Verify the file with ffprobe before you trust it. The command prints only the fields we care about.
ffprobe -v error -select_streams v:0 \
-show_entries stream=codec_name,width,height,r_frame_rate,nb_frames \
-of default=noprint_wrappers=1 build/background_loop.mp4
Here is the output you should see if everything went right:
codec_name=h264
width=1920
height=1080
r_frame_rate=30/1
nb_frames=300
If you would rather start from a ready-made animated clip than a still, the intro themes list their resolution, length and frame rate up front, which tells you quickly whether a clip fits a 1920×1080 canvas. Any short loop you already own works too, as long as it is 1920×1080 and its first and last frames match.
Create the scene and add the background (Step 3)
In the Scenes dock, click the plus button and name the new scene Starting Soon. Keep the name literal and plain, because the Lua script in Step 9 matches on it. Then click the plus in the Sources dock and choose Media Source. Name it BG Loop.
In the Media Source properties, tick Local File, browse to build/background_loop.mp4, and set these options:
- Loop: on. Without it the video freezes on its last frame after 10 seconds.
- Restart playback when source becomes active: on. The loop starts from frame 1 every time you enter the scene.
- Use hardware decoding when available: on. It can cut CPU use.
- Close file when inactive: off. Keeping the file open avoids a stutter when you switch back to this scene.
Press Ctrl+F (Cmd+F on macOS) to fit the source to the screen. If the loop is exactly 1920×1080 you will see no scaling at all. Drag the source to the bottom of the stack in the Sources list, since everything else goes above it.
One detail catches people: the video must have no audio track, or OBS adds a separate fader for it in the mixer, and it will play whenever the scene is active. We stripped audio in Step 2 with -an, so you should not see a new fader appear. If you do, right-click it in the Audio Mixer, open Advanced Audio Properties, and set it to Monitor Off, or rebuild the file without audio.
| Source type | Best use on this screen | Key setting | Common trap |
|---|---|---|---|
| Media Source | Looping background clip, music | Loop on, restart on active | Hidden audio track adds a fader |
| Image | Logo, still fallback | PNG alpha preserved | Oversized PNG scales blurry |
| Text (GDI+) on Windows | Title line, countdown from file | Read from file, outline | Font missing on another PC |
| Text (FreeType 2) on macOS and Linux | Same as above | Read from file | Fewer styling options |
| Browser | Live countdown from HTML | Refresh when scene becomes active | Local file path ignores the query string |
| Color Source | Solid panel behind text | Alpha under 100 percent | Covers the loop if left opaque |
Add the logo and text lines (Steps 4 and 5)
Step 4 is the logo. Add an Image source named Logo and point it to assets/logo.png. Press Ctrl+E to open Edit Transform and set the position by number, so it survives a restart and matches across scenes. Drop it in the upper center at roughly one third of the screen height. A logo that fills half the screen reads as a billboard, and a tiny one reads as a mistake.
Keep text and logo inside a safe area. Viewers on phones and in small player windows lose the outer edge of the picture to controls and overlays. A 5 percent margin all round, which is 96 pixels on the sides and 54 pixels top and bottom of a 1920×1080 canvas, keeps everything visible. That is a rule of thumb from broadcast layout, not a platform requirement, but it costs you nothing.
Font choice matters more than it seems. Thin weights vanish against a moving background, and fancy display faces make numerals hard to read. Pick a heavy sans-serif with clear digits, because the same family will style your countdown. Keep light text on a dark scene or dark text on a light scene, and avoid mid-tone text on a mid-tone background, which is the most common readability failure on waiting screens.
Add a second text source named Social Line for your handle or a schedule note. Make it half the size of the title. Two lines of text is the limit. A third line becomes a paragraph, and nobody reads a paragraph on a screen that disappears in five minutes.
If the text looks flat on top of a busy background, add a Color Source named Text Panel behind it. Set it to black with the opacity at about 40 percent and size it to the text block. Reorder so the panel sits above the loop but below the text. Quick test: squint at the screen. If you can still read the title, so can everyone else.
Build the countdown as a browser source (Step 6)
OBS has no built-in countdown source that runs by itself. The text source shows whatever string you give it, so the countdown has to come from somewhere else. A browser source is the cleanest option: one small HTML file, no plugin, and it restarts every time the scene becomes active if you tick the right box.
Save the following as html/countdown.html. It reads the countdown length from the URL, so you can change it without editing the file. Use ?m=10 for ten minutes, or ?at=19:30 to count down to a clock time.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
html, body { margin: 0; background: transparent; overflow: hidden; }
#wrap { width: 1920px; height: 300px; display: flex;
align-items: center; justify-content: center; }
#t { font: 700 220px/1 "Segoe UI", Arial, sans-serif; color: #ffffff;
letter-spacing: 6px; font-variant-numeric: tabular-nums;
text-shadow: 4px 4px 0 #000, -4px -4px 0 #000,
4px -4px 0 #000, -4px 4px 0 #000; }
</style>
</head>
<body>
<div id="wrap"><div id="t">00:00</div></div>
<script>
const q = new URLSearchParams(location.search)
const now = Date.now()
let end
if (q.get("at")) {
const [h, m] = q.get("at").split(":").map(Number)
const d = new Date()
d.setHours(h, m, 0, 0)
if (d.getTime() <= now) d.setDate(d.getDate() + 1)
end = d.getTime()
} else {
end = now + Number(q.get("m") || 5) * 60000
}
const el = document.getElementById("t")
function tick() {
const left = Math.max(0, Math.round((end - Date.now()) / 1000))
const mm = String(Math.floor(left / 60)).padStart(2, "0")
const ss = String(left % 60).padStart(2, "0")
el.textContent = mm + ":" + ss
if (left > 0) setTimeout(tick, 250)
}
tick()
</script>
</body>
</html>
Add it in OBS: plus in Sources, choose Browser, name it Countdown. Tick Local file and browse to html/countdown.html. Local files can ignore the query string, so if ?m=10 does nothing, untick Local file and enter file:///full/path/to/html/countdown.html?m=10 in the URL field instead. Set Width to 1920 and Height to 300. Then tick Refresh browser when scene becomes active, which restarts the timer each time you enter the scene, and tick Shutdown source when not visible so it stops using resources in your gameplay scene.
The 250 millisecond tick in the script is deliberate. A one-second timer drifts against the real clock, and viewers see the display skip a number now and then. Ticking four times a second and rounding keeps the display honest. The tabular-nums font setting stops the digits from jittering sideways as they change.
Test it right after the OBS 33 update. Because the browser engine changed so much, run through this checklist once. It takes 90 seconds.
- The digits render and count down once per second.
- The background is transparent, with no white or black box.
- Switching away and back restarts the timer.
- Your CPU use in the status bar stays flat while the scene is live.
Add a fallback countdown from a text file (Step 7)
Every starting soon screen needs a plan B. Browser sources are the best path, but they are also the part of OBS that changed most in version 33. Keep a plain fallback ready. A tiny Python script writes the remaining time to a text file twice a second, and a text source reads that file. No browser engine is involved, so nothing about the Chromium update can break it.
import pathlib
import sys
import time
minutes = int(sys.argv[1]) if len(sys.argv) > 1 else 5
out = pathlib.Path(__file__).with_name("countdown.txt")
end = time.time() + minutes * 60
while True:
left = max(0, int(round(end - time.time())))
m, s = divmod(left, 60)
out.write_text(f"{m:02d}:{s:02d}")
if left == 0:
break
time.sleep(0.5)
Save it as scripts/countdown.py and run python3 scripts/countdown.py 10 a minute before you go live. In OBS, add a Text source named Countdown Text, tick Read from file, and point it at scripts/countdown.txt. OBS rereads the file about once a second, which is plenty. Style it the same way as the title: bold, outlined, large.
Pick one countdown per scene, not both. Stacking the browser countdown and the file countdown makes a blurry double image the moment they drift half a second apart. Hide the one you are not using by clicking its eye icon, and keep it in the scene so you can flip over in a hurry.
The downside of this method is that you start the script by hand. That is why the browser source stays the default and the file version stays the lifeboat. If you stream from a separate PC, remember the script must run on the machine that runs OBS, since the text source reads a local file.
Add music and set the audio levels (Step 8)
Silence on a waiting screen looks like a broken stream. A quiet music bed fixes that and gives viewers something to set their own volume against. The licence matters more than the track: use music you own, made yourself, or licensed for live streaming, because a stream that gets muted or flagged is worse than silence. Check the licence text for the words live streaming before you commit to a track.
Normalize the file first so every track you use sits at the same level. This FFmpeg command trims the track to a clean length, fades the ends so the loop does not click, and sets a loudness target. The value of minus 18 is a working choice for a background bed, low enough that your microphone sits clearly above it when you talk.
ffmpeg -y -i assets/music.wav -t 180 \
-af "loudnorm=I=-18:TP=-1.5:LRA=7,afade=t=in:d=2,afade=t=out:st=176:d=4" \
-ar 48000 -c:a pcm_s16le build/music_bed.wav
In OBS, add a Media Source named Music Bed, pick the WAV, and tick Loop. Leave Restart playback when source becomes active unticked if you want the music to continue where it left off, which avoids replaying the start of the track every time you return to this scene. Then open Advanced Audio Properties from the gear menu in the Audio Mixer. Choose Monitor Off for the bed unless you want to hear it in your own headphones.
Two checks save a lot of grief. First, speak into your microphone while the music plays and watch the meters. Your voice should peak well above the music. Second, keep the music source only in this scene. Audio sources in OBS play while their scene is active, so switching to Live stops the bed, but if you ever add the same source to another scene, mute that copy.
Switch to the live scene automatically with Lua (Step 9)
A countdown that hits zero while you are still fiddling with your microphone is awkward. If you want OBS to cut to your live scene on its own, a short Lua script does it. OBS runs Lua scripts natively through Tools, then Scripts, so there is nothing to install.
The script arms a timer when you enter the Starting Soon scene and switches to a scene you name when the timer runs out. If you leave the scene early by hand, it disarms itself. Save it as scripts/auto_switch.lua.
obs = obslua
trigger_scene = "Starting Soon"
target_scene = "Live"
delay_seconds = 300
function script_description()
return "Switches to the live scene after a delay once the Starting Soon scene is shown."
end
function script_properties()
local p = obs.obs_properties_create()
obs.obs_properties_add_text(p, "trigger_scene", "Waiting scene", obs.OBS_TEXT_DEFAULT)
obs.obs_properties_add_text(p, "target_scene", "Scene to switch to", obs.OBS_TEXT_DEFAULT)
obs.obs_properties_add_int(p, "delay_seconds", "Seconds until switch", 10, 7200, 10)
return p
end
function script_defaults(settings)
obs.obs_data_set_default_string(settings, "trigger_scene", "Starting Soon")
obs.obs_data_set_default_string(settings, "target_scene", "Live")
obs.obs_data_set_default_int(settings, "delay_seconds", 300)
end
function script_update(settings)
trigger_scene = obs.obs_data_get_string(settings, "trigger_scene")
target_scene = obs.obs_data_get_string(settings, "target_scene")
delay_seconds = obs.obs_data_get_int(settings, "delay_seconds")
end
function do_switch()
obs.timer_remove(do_switch)
local scenes = obs.obs_frontend_get_scenes()
for _, s in ipairs(scenes) do
if obs.obs_source_get_name(s) == target_scene then
obs.obs_frontend_set_current_scene(s)
break
end
end
obs.source_list_release(scenes)
end
function on_event(event)
if event ~= obs.OBS_FRONTEND_EVENT_SCENE_CHANGED then return end
obs.timer_remove(do_switch)
local cur = obs.obs_frontend_get_current_scene()
if cur ~= nil then
if obs.obs_source_get_name(cur) == trigger_scene then
obs.timer_add(do_switch, delay_seconds * 1000)
end
obs.obs_source_release(cur)
end
end
function script_load(settings)
obs.obs_frontend_add_event_callback(on_event)
end
Load it with Tools, Scripts, the plus button, then pick the file. Set the three fields in the right-hand pane. Make the delay match your countdown: a 300 second delay pairs with ?m=5. The script does not know about the browser countdown, so the two are only in sync if you set the numbers yourself. Add a few seconds of slack to the delay if you want viewers to see 00:00 before the cut.
Create a second scene named Live first, or the script finds nothing to switch to. Watch the Script Log window (Tools, Scripts, Script Log) while testing. The script prints nothing on success, so if you want proof, add a print("switching") line inside do_switch. Test with a delay of 10 seconds before trusting it with a real stream.
| Scene | Purpose | Sources inside | How you leave it |
|---|---|---|---|
| Starting Soon | Waiting screen before you go live | BG Loop, Logo, Title Line, Countdown, Music Bed | Auto-switch script or hotkey |
| Live | Gameplay or main content | Capture, camera, alerts | Hotkey to Be Right Back |
| Be Right Back | Short break | Same loop, new text | Hotkey to Live |
| Stream Ending | Thanks, socials, next stream time | Same loop, outro text | Stop Streaming button |
| Technical Difficulties | Fallback if a capture fails | BG Loop, short message | Manual |
Make a stinger transition with an alpha channel (Step 10)
A stinger is a short animation that plays over the old scene and reveals the new one. It hides the cut for one second of effort. OBS plays the stinger as a video file and swaps the scenes at a point you choose, called the transition point. At 30 fps, frame 15 is the middle of a one-second clip, which is 500 milliseconds in. That is the moment the new scene should appear, while the animation covers the screen.
Export your animation as a PNG sequence with transparency, 30 frames named stinger_001.png to stinger_030.png, from whatever tool you animate in. Then encode it to WebM with an alpha channel. The -auto-alt-ref 0 flag is not optional for VP9 with alpha, since without it the alpha plane gets dropped.
ffmpeg -y -framerate 30 -i assets/stinger_%03d.png \
-c:v libvpx-vp9 -pix_fmt yuva420p -b:v 0 -crf 28 -auto-alt-ref 0 \
-an build/stinger.webm
If your FFmpeg lacks libvpx-vp9, or you hit playback trouble, use ProRes 4444 in a MOV container instead. The file is much larger but is a dependable alpha format.
ffmpeg -y -framerate 30 -i assets/stinger_%03d.png \
-c:v prores_ks -profile:v 4444 -pix_fmt yuva444p10le \
-an build/stinger.mov
In OBS, find the Scene Transitions dock, click the plus, and choose Stinger. Name it Logo Swipe. Pick your file. Set Transition Point Type to Frame and enter 15. If your stinger has no alpha channel, switch to the track matte mode in the same dialog instead, which uses a black-and-white matte to cut the reveal. Finally, select Logo Swipe as the active transition and click a scene to try it. Studio Mode helps here, since you can preview the swap before it goes out.
Keep stingers short. One second is a flourish, three seconds is an interruption. For a feel of how a few seconds of motion reads on screen, the sample intros make a quick reference for pacing.
Test the screen for Twitch and YouTube (Step 11)
Twitch and YouTube both take whatever OBS sends, so a Twitch starting soon screen and a YouTube one can be the same scene. What changes is the surrounding workflow. On Twitch you press Start Streaming and your channel goes live, so the waiting screen is the first thing viewers see the instant you do. On YouTube you can create a scheduled live event in advance, and viewers can open its page before you start, so the waiting screen only appears once the feed is up. Check each dashboard’s stream health view to confirm incoming video before you tell anyone to tune in.
For encoder numbers, read the platform’s own current guidance rather than copying a figure from a blog. Resolution, bitrate and keyframe interval limits change with the service and with your upload speed. The scene built here is a mostly static layout with a gentle loop, which is easy to encode, so it will not be the part that strains your connection. Your game will.
Record before you stream. Press Start Recording in OBS, sit in the Starting Soon scene for 30 seconds, switch to Live with the stinger, and stop. Open the MKV and check these things: the loop has no jump, the text is readable at one quarter size, the music sits under your voice, and the stinger swaps at the right moment. Playing it back in a small window is the best proxy for a viewer on a phone.
ffprobe -v error -select_streams v:0 \
-show_entries stream=codec_name,width,height,r_frame_rate \
-of default=noprint_wrappers=1 test_recording.mkv
The recording should report the size and frame rate you set in OBS. If the frame rate reads lower than 30, your machine is dropping frames and you should look at CPU use before you go live.
One last habit: watch your own channel on a second device for the first few seconds of every stream. Delay between OBS and the viewer varies by service and by latency setting, so do not cut to Live based on what you see in OBS alone. Give the screen a few extra seconds of runway.
The complete working project
Here is everything assembled in one place. After you finish the steps above, your folder looks like this:
starting-soon-kit/
assets/
background.png
logo.png
music.wav
stinger_001.png ... stinger_030.png
build/
background_loop.mp4
music_bed.wav
stinger.webm
html/
countdown.html
scripts/
countdown.py
auto_switch.lua
build.sh
The script below rebuilds every media file from the raw assets and checks the result. Run it whenever you swap the background or the music. It stops at the first error, so a missing file cannot slip past quietly.
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
mkdir -p build
echo "1/3 background loop"
ffmpeg -loglevel error -y -loop 1 -framerate 30 -t 10 -i assets/background.png \
-vf "scale=3840:2160,zoompan=z='1.06+0.05*sin(2*PI*on/300)':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=1:s=1920x1080:fps=30,format=yuv420p" \
-c:v libx264 -crf 18 -preset slow -an -movflags +faststart build/background_loop.mp4
echo "2/3 music bed"
ffmpeg -loglevel error -y -i assets/music.wav -t 180 \
-af "loudnorm=I=-18:TP=-1.5:LRA=7,afade=t=in:d=2,afade=t=out:st=176:d=4" \
-ar 48000 -c:a pcm_s16le build/music_bed.wav
echo "3/3 stinger"
if ls assets/stinger_*.png >/dev/null 2>&1; then
ffmpeg -loglevel error -y -framerate 30 -i assets/stinger_%03d.png \
-c:v libvpx-vp9 -pix_fmt yuva420p -b:v 0 -crf 28 -auto-alt-ref 0 -an build/stinger.webm
else
echo "no stinger frames found, skipping"
fi
echo "checking background loop"
frames=$(ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames \
-of default=noprint_wrappers=1:nokey=1 build/background_loop.mp4)
[ "$frames" = "300" ] || { echo "expected 300 frames, got $frames"; exit 1; }
echo "ok"
The expected console output is short. If you see all five lines and no error, the media is ready:
1/3 background loop
2/3 music bed
3/3 stinger
checking background loop
ok
Then build the OBS side in this order, bottom to top: BG Loop, Text Panel, Logo, Title Line, Social Line, Countdown and Music Bed in the Starting Soon scene. Add the Live scene. Add the Logo Swipe stinger. Load auto_switch.lua. Finally, export your scene collection from the Scene Collection menu as a JSON file and keep it in the project folder, so a reinstall takes two minutes instead of twenty.
Do one full dry run from a cold start. Open OBS, switch to Starting Soon, let the 10-second test delay run out, and confirm the cut to Live happens with the stinger. Before each real stream, the routine is short: edit the title line, set the countdown with the minutes or the clock time, restart the countdown by re-entering the scene, and confirm the music sits under your voice. That is a 60-second job once the kit exists.
Common pitfalls
These are the mistakes that show up most in waiting screens, and each one costs viewers in the first ten seconds.
- Loop with a visible jump. A background that snaps back at the seam reads as a glitch. Build the loop with the sine zoom above or crossfade the ends, and watch five passes before you ship it.
- Music you do not have the rights to stream. A track that is fine in a video can still be blocked on a live stream. Keep the licence text with the file and read it for the words live streaming.
- Absolute file paths. OBS stores the full path to each media file. Move the project folder and every source goes blank. Keep the kit in one place and re-point sources after a move.
- Countdown that never restarts. If you forget Refresh browser when scene becomes active, the timer runs once and sits at 00:00 for the rest of the night.
- Too much text. Two lines is the cap. Three lines, a schedule, a donation goal and a poll turn the screen into noise.
- Ignoring the safe area. Text pressed against the edges gets clipped in small players and on mobile. Stay inside a 5 percent margin.
- Skipping a test recording. Every problem in this tutorial is easier to catch in a 30-second local recording than live in front of an audience.
- Leaving a beta installed. The OBS team pointed production users to the stable release. If you tried a 33.0 beta or release candidate, move to 33.0.1.
Most of these come down to the same habit: look at the screen the way a stranger would. Pause on it for two seconds. If you cannot name the show, the topic and the start time in that time, trim something.
Troubleshooting
When something breaks, check the cheap causes first: the file path, the box ticked or unticked, then the source order. The list below covers the failures that come up most with this build.
- The browser source shows a black or white box. The HTML has a solid background or the page failed to load. Confirm
background: transparentin the CSS, open the file in a normal browser to check it works, and use Refresh cache of current page in the source properties. - The countdown ignores the query string. Some local-file setups drop
?m=10. Untick Local file and use afile:///URL, or hard-code the minutes in the script. - The countdown stays at 00:00 after you return to the scene. Tick Refresh browser when scene becomes active, and check that Shutdown source when not visible is on.
- The loop stutters on switching. Turn off Close file when inactive on the Media Source and keep hardware decoding on. If it still stutters, re-encode with a higher CRF such as 23, which gives a smaller file that is easier to decode.
- The loop jumps at the seam. Run ffprobe and confirm 300 frames. Re-render with the zoom period equal to the frame count.
- The stinger shows a black box instead of transparency. The alpha plane was lost. Re-encode with
-pix_fmt yuva420pand-auto-alt-ref 0, use the ProRes 4444 version, or switch to track matte mode. - The stinger swaps scenes too early or too late. Change the transition point. Frame 15 of 30 is the midpoint, so move it toward the frame where your animation fully covers the screen.
- The Lua script does nothing. Open Script Log and look for errors. The two usual causes are scene names that do not match exactly, including capital letters, and a delay still set to its default of 300 seconds while you test with a shorter countdown.
- A new audio fader appears for the background. The clip has an audio track. Rebuild with
-anor set that fader to Monitor Off and mute it. - OBS crashes at startup after logging in. If you are on 33.0.0, update. The 33.0.1 hotfix fixed a startup crash tied to being logged into a service integration.
- A plugin or overlay that worked before OBS 33 misbehaves. Third-party plugins still load from the legacy locations until OBS Studio 34.0, but browser-based overlays now run on a newer engine. Test them, check the plugin’s own page for an update, and fall back to the text-file countdown from Step 7.
- OBS will not install on Ubuntu 24.04. The official OBS 33 package targets Ubuntu 26.04 and dropped 24.04. Upgrade the OS, or look at a Flatpak build.
If none of those match, change one thing at a time and retest. Rebuilding the scene from scratch is rarely needed. Exporting your scene collection as JSON before you experiment gives you a way back.
Advanced tips
Once the basic kit works, a few small upgrades pay off. None are required, and each takes under ten minutes.
Reuse the loop for every waiting scene. Create Be Right Back and Stream Ending as duplicates of Starting Soon, then change only the text. In OBS you can add the same Media Source to several scenes, and the loop keeps its look across all of them. Duplicate the scene with a right-click rather than rebuilding the starting soon screen, and rename the text lines. Your channel then feels like one product instead of a pile of unrelated screens.
Drive the screen from a hotkey, not a mouse. Open Settings, then Hotkeys, and bind a key to each scene. When your hands are on the keyboard in a game, you cannot click a scene. Use keys that games do not use, such as a modifier plus a function key. If you have a stream deck or a second keyboard, bind those instead. Pair this with Studio Mode when you want a preview before the cut, which suits events and interviews.
Show chat without clutter. Viewers who arrive early often want to talk. A chat box on the waiting screen gives them something to do. Add it as a second browser source from the platform’s chat pop-out, keep it to a narrow column, and leave the center of the frame free for the countdown. Keep chat off the Live scene if your game already uses the space.
Reuse the loop outside OBS. Cut a short vertical teaser from the same background for Shorts and Reels. YouTube’s blog highlighted Shorts series on October 27, 2026, a format that lets creators organize Shorts into seasons and episodes, and the post is on the YouTube blog. A recurring teaser fits that format if your stream has a regular show.
Keep a vertical or 60 fps variant on file. Duplicate the project folder, change the canvas, rerun build.sh with a 60 fps loop (set the sine period to 600 for a 10-second clip), and save the result as its own scene collection. You pay once in setup time and switch profiles in seconds.
Questions creators ask
How long should a starting soon screen run?
Five minutes is a sensible default. It gives early viewers time to arrive without making them sit through filler. If you stream on a fixed schedule, count down to the clock time with ?at=19:30 in the countdown URL, and the display stays correct even if you enter the scene late.
Does the same screen work on Twitch and YouTube?
Yes. OBS outputs one video feed, and both platforms receive whatever scene is live. The scene needs no changes, only the service and stream key in OBS settings. The surrounding steps differ, such as scheduling a live event on YouTube.
Do I need a paid plugin for the countdown?
No. The HTML browser source in Step 6 and the Python text file in Step 7 are both free and need no plugin. Plugins can add features, but they come from third parties, so check each plugin’s own page for support on your OBS version.
Which OBS version should I use?
Use the latest stable release, which is OBS Studio 33.0.1 as of October 31, 2026. Avoid beta and release candidate builds for live work. On Linux, the official package targets Ubuntu 26.04.
Why does my countdown show a white background?
Either the page sets a solid background or the browser source is cached. Set background: transparent on both html and body, then use the cache refresh button in the source properties. After the OBS 33 browser engine update, test again even if it worked before.
Can I use one video file as the whole screen instead?
You can, and it is the simplest path: one Media Source with the loop on. You lose the live countdown, because a baked-in timer runs out and then repeats. A looping video with no timer plus a browser countdown on top is the better setup, and it is what this tutorial builds.
How do I keep the screen light on my CPU?
Keep the loop at 1920×1080 and 30 fps, turn on hardware decoding, tick Shutdown source when not visible on the browser source, and avoid stacking many effect filters. A single H.264 clip plus a small HTML page is a light load next to the game you are about to stream.
- Your Video a channel-style intro theme
- Intro themes stream and channel intros
- Sample videos finished Vipid intros
- Vipid intro maker make a custom intro in the browser
Theo Vance
Theo Vance is the Intros & Templates Editor at Vipid, where he covers intro and outro makers, template libraries for CapCut, Canva and the major editors, slideshow and video-card tools, and stream starting screens. He compares makers on what matters before you hit render: watermark, export resolution, length limits, licence and price, and dates every check. He also looks after the Vipid theme archive, the 2011–2016 intros the site was built on.
![Free Twitch Overlays [2026]: 5 Sources, $0 vs $27/mo](https://ivipid.com/blog/wp-content/uploads/2026/11/free-twitch-overlays-2026-gen-800x450.webp)
![OBS vs ShadowPlay vs Medal [2026]: 3 Free Recorders](https://ivipid.com/blog/wp-content/uploads/2026/11/obs-vs-shadowplay-vs-medal-2026-gen-800x450.webp)
![OBS vs Streamlabs [2026]: $0 vs $27/mo for Ultra](https://ivipid.com/blog/wp-content/uploads/2026/11/obs-vs-streamlabs-2026-gen-800x450.webp)