Stream Control and OBS - Scoreboards and more

Status
Not open for further replies.

Jack0r

The Helping Squad
Forum Moderator
#1
Today I have an interesting guide for a few different types of streams. Either you are a professional player and want to add some infos or a scoreboard to your stream or you are a shoutcaster and want to show what teams are playing, use Lower Thirds to tell the viewers who is commentating or just do some nice animations with dynamic text you can change in an external program and while the scene is not running, or is running.
So whats up with all this sorcery you might say, but its actually pretty simple, thanks to the work of a guy you can follow under @farpenoodle on twitter. First of all, a little example of how it can look. Be aware, those rectangles fly in, show the text and fly out after a specified time!

You will need the following things:

On the StreamControl page you can already find example files, but I created a little package for you guys to get you rolling. The main credit also goes to farpnut, I just used his examples to create some more different options. Grab the package here and the needed layout file for Stream Control here.

OR you grab this AiO package which include updated html files and animations that can be used more dynamically (re-appearing slide-ins).

You can watch this Video or read on to find out how to use it.

First of all, extract all files you downloaded:
  • Stream Control
    • either in its own folder or into the OBS folder, does not matter
  • OBS / CLR Browser Plugin
    • of course install the Plugin into the OBS\plugins folder, location of OBS does not matter
  • Browser Files
    • if you downloaded my browser files you can extract them to your stream control folder or any location you like, its just necessary that you select this location in the next step
  • browserfiles_layout.xml
    • location does not matter, it will be selected in the next step

Because now we are going to setup Stream Control. When you first load it, you should see a interface like this:

We need to click that gear icon and go into the configuration. Now we have to select the folder in which you extracted the browser files instead of selecting an XSplit Path, and for the layout file we select our browserfileslayout.xml. After that you can click ok and should see a picture like this:

You can now already enter and use the fields to your liking, click the little Floppy icon to save everything and "push" it live. Of course, before we can see something on our Stream, we have to add some necessary sources into OBS.

In OBS you have to add a CLR Browser source. For my example html files you can just click on the little question mark at the end of the url field and select the html file you want to add. The correct size for each of the examples can be below, be aware some of them will work with different sizes and you can of course scale the added source to fit your scene:
  • Commentator
    • width 500 | height 1080
  • Lower Third 1 and 2 Line
    • width 1920 | height 1080
  • ScoreBoard 1 / 2 / 3
    • width 1280 | height 100-200
  • Slide left/right
    • width 500 | height 1080
  • Versus
    • width 1920 | height 1080

Now it actually does not matter when you update your settings in Stream Control, the program saves your settings to a streamcontrol.xml inside the browserfiles folder (on my setup example). So whenever one of the html files get loaded you will see the updated text on screen. You can also edit pretty much everything to your liking. Change the animations, add more text fields to Stream Control, or use Tabs to sort the different options inside Stream Control (see farpnut's original layout.xml). Just take a look at the html files and especially the java script part. Using jstween you can do a lot of things.

For the Browser Plugin I want to mention one last thing. When using swf files instead of html files or URL's, select the "Intercept request and apply template" checkbox and most Shockwave Flash Files should work. You have to set StreamControl to write its xml file to the \**\OBS\ folder instead of the folder of your html files. If you get a gray message you need "Flash for other Browsers" from the Adobe page. And if you get just a black box you have to activate Single Process mode under Settings -> Browser -> Runtime. Set "SingleProcess" to True, save and restart OBS, then check the step mentioned before if you get a gray message.

As always, comment with your Ideas, suggestions and everything else you want to share that fits this topic!

PS: If someone is able to write an animation-wise functional version of the script that starts the animation again as soon as you change the text. I had problems getting this to work without visible flaws in the animation. This would be very useful for the Lower Thirds to do news-like fly-ins.
This has been fixed in the AiO package!
 

merl

New Member
#2
Re: [Guide/Video] Stream Control and OBS - Scoreboards and m

Thanks, these jquery browserfiles are great!

I'm going to create a webclient that essentially does what streamcontrol does, so people can control the scoreboards's XML via a web-client.
 

d3v

New Member
#3
Re: [Guide/Video] Stream Control and OBS - Scoreboards and m

Hi,
I'm trying this out with my own custom overlay that I used to use on XSplit, while the SWF loads, the text does not update. I'm guessing this is because Stream Control isn't writing the XML file in the correct place. My question would then be where should I tell Stream Control to write the XML file (and if there's a specific folder structure).
 

Jack0r

The Helping Squad
Forum Moderator
#4
Re: [Guide/Video] Stream Control and OBS - Scoreboards and m

If I remember correct, the file just has to be saved in the same location as your swf file and it should work :)
 
#5
Re: [Guide/Video] Stream Control and OBS - Scoreboards and m

This is quite neat guide. I use it for amateur TW tournaments we host.

I would like to ask for help adjusting it for my needs - I try to get rid of all country/flags related code in ScoreBoard-ths_gray_.html but I always end up breaking it.
I want make a minimal working template for just two names and a score.
 

Jack0r

The Helping Squad
Forum Moderator
#6
Re: [Guide/Video] Stream Control and OBS - Scoreboards and m

html file:
Code:
<html>
<head>
	<link rel="stylesheet" href="css/stylesheetv2.css" type="text/css" charset="utf-8">
	<script src="js/jquery-2.0.2.min.js" type="text/javascript" charset="utf-8"></script>
	<script src="js/jstween-1.1.min.js" type="text/javascript" charset="utf-8"></script>
	<script src="js/countries.js" type="text/javascript" charset="utf-8"></script>
	<script type="text/javascript">
			
			var timestampOld;
			var timestamp;
			var pName1;
			var pScore1;
			var pName2;
			var pScore2;
			var mText3;
			var mText4;
			
			var xmlDoc;
		
			var xhr = new XMLHttpRequest();
		
			var animating = false;
			var doUpdate = false;
			
			function init() {

				xhr.overrideMimeType('text/xml');
				
				var timeout = this.window.setInterval(function() {
					pollHandler();
				}, 250);
			
				$('#pName1').html('');
				$('#pScore1').html('');
				$('#pName2').html('');
				$('#pScore2').html('');
				$('#mText3').html('');
				$('#mText4').html('');
				$('#board').tween({
				   top:{
					  start: '-100',
					  stop: '0',
					  units: 'px',
					  time: 0,
					  duration: 0.8,
					  effect:'easeOut'
				   }
				});
				
				$.play();
			}
			
			function pollHandler()
			{
			  loadData();
			  if (timestamp != timestampOld) {
				  doUpdate = true;
			  }
			  if (!animating && doUpdate) {
				  updateBoard();
			  }
			}
			
			function loadData() {
				xhr.open('GET', 'streamcontrol.xml');
				xhr.send();
				xhr.onreadystatechange = function(){
						xmlDoc = xhr.responseXML;
						
						pName1 = getValueFromTag(xmlDoc,'pName1');
						pName2 = getValueFromTag(xmlDoc,'pName2');
						pScore1 = getValueFromTag(xmlDoc,'pScore1');
						pScore2 = getValueFromTag(xmlDoc,'pScore2');
						mText3 = getValueFromTag(xmlDoc,'mText3');
						mText4 = getValueFromTag(xmlDoc,'mText4');						
						timestampOld = timestamp;
						timestamp = getValueFromTag(xmlDoc,'timestamp');
						
				}
			}
			
			function updateBoard() {
				if ($('#pName1').html() != pName1) {
					animating = true;
					$('#pName1').tween({
						left:{
						  start: 126,
						  stop: 275,
						  units: 'px',
						  time: 0,
						  duration: 0.5,
						  effect:'easeIn'
						},
						opacity: {
						  start: 100,
						  stop: 0,
						  time: 0,
						  duration: 0.5,
						  effect: 'easeIn'
						},
						onStop: function(){
							$('#pName1').html(pName1);
						}
					});
					
					$('#pName1').tween({
						left:{
						  start: 275,
						  stop: 126,
						  units: 'px',
						  time: 0.5,
						  duration: 0.5,
						  effect:'easeOut'
						},
						opacity: {
						  start: 0,
						  stop: 100,
						  time: 0.5,
						  duration: 0.5,
						  effect: 'easeOut'
						},
						onStop: function(){
							animating = false;
						}
					});
				}
				
				if ($('#pName2').html() != pName2) {
					animating = true;
					$('#pName2').tween({
						left:{
						  start: 775,
						  stop: 675,
						  units: 'px',
						  time: 0,
						  duration: 0.5,
						  effect:'easeIn'
						},
						opacity: {
						  start: 100,
						  stop: 0,
						  time: 0,
						  duration: 0.5,
						  effect: 'easeIn'
						},
						onStop: function(){
							$('#pName2').html(pName2);
						}
					});
					
					$('#pName2').tween({
						left:{
						  start: 675,
						  stop: 775,
						  units: 'px',
						  time: 0.5,
						  duration: 0.5,
						  effect:'easeOut'
						},
						opacity: {
						  start: 0,
						  stop: 100,
						  time: 0.5,
						  duration: 0.5,
						  effect: 'easeOut'
						},
						onStop: function(){
							animating = false;
						}
					});
				}
				
				if ($('#pScore1').html() != pScore1) {
					animating = true;
					$('#pScore1').tween({
						opacity: {
						  start: 100,
						  stop: 0,
						  time: 0,
						  duration: 0.5,
						  effect: 'easeIn'
						},
						onStop: function(){
							$('#pScore1').html(pScore1);
						}
					});
					
					$('#pScore1').tween({
						opacity: {
						  start: 0,
						  stop: 100,
						  time: 0.5,
						  duration: 0.5,
						  effect: 'easeOut'
						},
						onStop: function(){
							animating = false;
						}
					});
				}
				
				if ($('#pScore2').html() != pScore2) {
					animating = true;
					$('#pScore2').tween({
						opacity: {
						  start: 100,
						  stop: 0,
						  time: 0,
						  duration: 0.5,
						  effect: 'easeIn'
						},
						onStop: function(){
							$('#pScore2').html(pScore2);
						}
					});
					
					$('#pScore2').tween({
						opacity: {
						  start: 0,
						  stop: 100,
						  time: 0.5,
						  duration: 0.5,
						  effect: 'easeOut'
						},
						onStop: function(){
							animating = false;
						}
					});
				}
				
				if ($('#mText3').html() != mText3) {
					animating = true;
					$('#mText3').tween({
						opacity: {
						  start: 100,
						  stop: 0,
						  time: 0,
						  duration: 0.5,
						  effect: 'easeIn'
						},
						onStop: function(){
							$('#mText3').html(mText3);
						}
					});
					
					$('#mText3').tween({
						opacity: {
						  start: 0,
						  stop: 100,
						  time: 0.5,
						  duration: 0.5,
						  effect: 'easeOut'
						},
						onStop: function(){
							animating = false;
						}
					});
				}
				
				if ($('#mText4').html() != mText4) {
					animating = true;
					$('#mText4').tween({
						opacity: {
						  start: 100,
						  stop: 0,
						  time: 0,
						  duration: 0.5,
						  effect: 'easeIn'
						},
						onStop: function(){
							$('#mText4').html(mText4);
						}
					});
					
					$('#mText4').tween({
						opacity: {
						  start: 0,
						  stop: 100,
						  time: 0.5,
						  duration: 0.5,
						  effect: 'easeOut'
						},
						onStop: function(){
							animating = false;
						}
					});
				}
				
				
				$.play();
				
				doUpdate = false;
			}
			
			function getValueFromTag (xmlDoc,tag) {
				if (xmlDoc.getElementsByTagName(tag).length != 0 ) {
					if (xmlDoc.getElementsByTagName(tag)[0].childNodes.length == 0) {
							return '';
						} else {
							return xmlDoc.getElementsByTagName(tag)[0].childNodes[0].nodeValue;
					}
				} else {
					return '';
				}
			}
			
	</script>
</head>
<body onLoad="init()">
	<div id="board">
		<div id="pFlag1"></div>
		<div id="pName1">Player 1</div>
		<div id="pScore1">99</div>
		<div id="pFlag2"></div>
		<div id="pName2">Player 2</div>
		<div id="pScore2">99</div>
		<div id="mText3">Test</div>
        <div id="mText4">Test2</div>
	</div>
</body>
</html>

css file:
Code:
@font-face {
    font-family: 'SansationRegular';
    src: url('Sansation_Regular-webfont.eot');
    src: url('Sansation_Regular-webfont.eot?#iefix') format('embedded-opentype'),
         url('Sansation_Regular-webfont.woff') format('woff'),
         url('Sansation_Regular-webfont.ttf') format('truetype'),
         url('Sansation_Regular-webfont.svg#SansationRegular') format('svg');
    font-weight: normal;
    font-style: normal;

}

@font-face {
    font-family: 'SansationBold';
    src: url('Sansation_Bold-webfont.eot');
    src: url('Sansation_Bold-webfont.eot?#iefix') format('embedded-opentype'),
         url('Sansation_Bold-webfont.woff') format('woff'),
         url('Sansation_Bold-webfont.ttf') format('truetype'),
         url('Sansation_Bold-webfont.svg#SansationBold') format('svg');
    font-weight: normal;
    font-style: normal;

}

body {
	margin:0px;
	background-color: rgba(0, 0, 0, 0);
	font-family: 'SansationRegular';
	color:#FFFFFF;
}

#board {
	position:absolute;
	top:0px;
	left:0px;
	width:1280px;
	height:100px;
	background-image:url('../images/game2.png');
}

#pName1 {
	position: absolute;
	left: 126px;
	top: 13px;
	width: 386px;
	font-size: 20px;
	text-align: left;
	color: #000;
}
#pName2 {
	position: absolute;
	left: 775px;
	top: 13px;
	width: 384px;
	font-size: 20px;
	text-align: right;
	color: #000;
}
#pScore1 {
	position:absolute;
	left:511px;
	top:13px;
	width:47px;
	font-size:20px;
	text-align:center;
}
#pScore2 {
	position:absolute;
	left:722px;
	top:13px;
	width:47px;
	font-size:20px;
	text-align:center;
}
#mText3 {
	color: #FFFFFF;
	position:absolute;
	left:560px;
	top:11px;
	width:160px;
	font-size:11px;
	font-family: 'SansationBold';
	text-align:center;
}
#mText4 {
	color: #FFFFFF;
	position:absolute;
	left:560px;
	top:33px;
	width:160px;
	font-size:11px;
	font-family: 'SansationBold';
	text-align:center;
}

I just quickly removed the flags and resized the Name tags a bit, just edit it further to your liking =)
 
#7
Re: [Guide/Video] Stream Control and OBS - Scoreboards and m

Thank you Jak0r!

I tried to do pretty much the same, but as result of my cuts it usually just stopped updating text on a screen^^

EDIT:
Also I am getting whole bunch of this messages on log:

Code:
11:45:39: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:39: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:39: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:39: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:39: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:39: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:39: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:40: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:40: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:40: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:40: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
11:45:40: CLRHost:: Browser 1: Uncaught TypeError: Cannot call method 'getElementsByTagName' of null @http://absolute/G:/Windows_user/Downloads/stream%20workshop/_steam_control/test.html296
And they make log quite big by the end of stream.

Test.html is the file you posted. Could it be because not all the values in streamcantrol.xml are initialized?
 

Jack0r

The Helping Squad
Forum Moderator
#8
Re: [Guide/Video] Stream Control and OBS - Scoreboards and m

Hmm I checked the original file from farpnut. It apparently produces the same error, although everything works in both versions.
I will have to talk to faruton if he knows of how we can get rid of the error message maybe. My tests also had produced some pretty big logfiles :D But OBS ran fine and everything worked, so I didnt check the logs earlier!
 
#9
Re: [Guide/Video] Stream Control and OBS - Scoreboards and m

As a random though: I wonder if it's possible to write similar scripted html to replace SteamControl software itself. Html with entry fields that saves data in file.
It should make it easier to use on second monitor as additional tab in a browser alongside stream chat instead of separate window which will help when there is too many windows open^^
 
#10
In the versus css file, is it possible to use steamcontrol to point to different team1 and team2 images rather than having to edit the css file directly every time?
 

Jack0r

The Helping Squad
Forum Moderator
#12
Archive Section of the Forum -> No, this topic is no more active.
You can still use Farpnuts software though.
 
Status
Not open for further replies.
Top