The Scalable Pixel Streaming Frontend is a library of HTML, CSS and TypeScript code that runs in client web browsers to help users connect to Scalable Pixel Streaming applications and interact with them. It is able to achieve this by consuming the Pixel Streaming Frontend and UI libraries and by extending their signalling server and WebSocket packages the Pixel Streaming Frontend can be configured to work with Scalable Pixel Streaming signalling severs.
For the base functionality for Pixel Streaming and its UI capabilities the Scalable Pixel Streaming Frontend consumes the Epic Games Pixel Streaming Frontend and UI Frontend:
The Pixel Streaming Frontend contains all the base functionality:
- WebSocket handling.
- Data channel handling.
- UE message handling.
- Mouse and keyboard interaction handling.
- Video and audio stream handling.
- Logic for: AFK, FreezeFrames, Mic, TURN, SDP.
The Pixel Streaming Frontend UI contains all the functionality for UI components:
- Text, Action and AFK Overlays.
- CSS styling.
- UI display settings.
- UE stream data.
The library includes all of the custom signalling logic that Scalable Pixel Streaming signalling servers require to work. The library can be obtained either through GitHub or NPM. The library must be initialised via HTML and Javascript. It is written in TypeScript, but configured to export as a UMD module and can be consumed by plain JavaScript and most JavaScript frameworks.
Our TypeScript example is a simple HTML, CSS, and TypeScript implementation that initialises the SPS frontend library by instantiating the library components and starting a connection to the signalling server.
Download the SPS frontend source code from GitHub.
SPS frontend packages contain several NPM scripts that can build the library and example implementation for either development or production. When building for development, source maps for debugging will be enabled. When building for production, source maps will be disabled, reducing console output and minifying the distributed JavaScript files. Below is a list of NPM scripts for both the library and example implementation with their respective commands.
First, install all required dependencies by running this command from the library
directory:
npm install
: Install the frontend library dependencies
The following build scripts must be executed from the same directory:
npm run build-dev
: Build the library in development modenpm run build-prod
: Build the library in production mode
The library must be installed before executing example scripts. All example scripts must be executed from the examples/typescript
directory:
npm run build-dev
: Build the library in development modenpm run build-prod
: Build the library in production modenpm run serve-dev
: Serve the example locally using the library in development modenpm run serve-prod
: Serve the example locally using the library in production modenpm run symlink
: Link the library to the example for consumption
Alternatively, you can run the build all scripts from the examples/typescript
directory to install and link the library and the example at the same time:
npm run build-all-dev
: Build the library and the example in development mode and link the library to the example for consumptionnpm run build-all-prod
: Build the library and the example in production mode and link the library to the example for consumption
- If your project includes a
package.json
file, run the following command in the same directory:
npm i @tensorworks/libspsfrontend
- Import your desired components from the library package
"@tensorworks/libspsfrontend"
The following example for initialising the library is based on the TypeScript example provided on GitHub.
- Import all the required objects, types, and packages from the SPS frontend library:
import {Config, PixelStreaming, SPSApplication, TextParameters, PixelStreamingApplicationStyle} from "@tensorworks/libspsfrontend";
- Apply default styling from Epic Games Pixel Streaming frontend:
export const PixelStreamingApplicationStyles = new PixelStreamingApplicationStyle();
PixelStreamingApplicationStyles.applyStyleSheet();
- Create a
webSocketAddress
variable, so that the WebSocket URL could be modified if a user wishes to inject their own WebSocket address at load time:
let webSocketAddress = "";
- Create a
document.body.onload
function to automate the activation and creation of the remaining steps:
document.body.onload = function () {
// steps 5-8 go in here
}
- Create the Pixel Streaming
config
object and ensure thatuseUrlParams
is true, andinitialSettings
contains{ OfferToReceive: true, TimeoutIfIdle: true }
. This is important as the SPS signalling server can only receive the offer to connect.TimeoutIfIdle
enables the AFK timeout by default, so that any unattended sessions close and stop consuming unnecessary cloud GPU resources:
const config = new Config({ useUrlParams: true, initialSettings: { OfferToReceive: true, TimeoutIfIdle: true } });
- Create an if statement that will make use of the
webSocketAddress
variable if one is included:
if(webSocketAddress != ""){
config.setTextSetting(TextParameters.SignallingServerUrl, webSocketAddress)
}
- Create an instance of the
PixelStreaming
object calledstream
and an instance of theSPSApplication
object calledspsApplication
:
// Create stream and spsApplication instances that implement the Epic Games Pixel Streaming Frontend PixelStreaming and Application types
const stream = new PixelStreaming(config);
// Create our SPS application and pass it some UI configuration options.
// Note: There are more options than this if you need them (e.g. turning off certain UI elements).
const uiOptions: UIOptions = {
stream: stream,
onColorModeChanged: (isLightMode) => PixelStreamingApplicationStyles.setColorMode(isLightMode) /* Light/Dark mode support. */
};
// Create our application
const spsApplication: SPSApplication = new SPSApplication(uiOptions);
- Append the
spsApplication.rootElement
inside a DOM element of your choice or inject directly into the body of the web page, like in the TypeScript example:
document.body.appendChild(spsApplication.rootElement);
//OR
document.getElementById("myElementId").appendChild(spsApplication.rootElement);
A default index implementation would look like this:
import {Config, PixelStreaming, SPSApplication, TextParameters, PixelStreamingApplicationStyle} from "@tensorworks/libspsfrontend";
export const PixelStreamingApplicationStyles = new PixelStreamingApplicationStyle();
PixelStreamingApplicationStyles.applyStyleSheet();
let webSocketAddress = "";
document.body.onload = function () {
const config = new Config({ useUrlParams: true, initialSettings: { OfferToReceive: true, TimeoutIfIdle: true } });
if(webSocketAddress != ""){
config.setTextSetting(TextParameters.SignallingServerUrl, webSocketAddress)
}
const stream = new PixelStreaming(config);
const spsApplication = new SPSApplication({
stream,
onColorModeChanged: (isLightMode) => PixelStreamingApplicationStyles.setColorMode(isLightMode) /* Light/Dark mode support. */
});
document.body.appendChild(spsApplication.rootElement);
}
When serving the SPS frontend, it will build a default WebSocket address to connect to, based on the address of the current window of the webpage. If the WebSocket address matches what is created by default, then no further steps are required. Users can override the default by using the setTextSetting
method on the config
instance. Refer to Basics to initialising and consuming the library, steps 3 and 6.
In the TypeScript example, there is a .env.example
file containing a filler URL in the WEBSOCKET_URL
line. This file can be used to hard code a WebSocket address that can be consumed by the example as shown above. This example is able to work with the help of the dotenv NPM package in the webpack.common.js
file in the TypeScript example. To implement this example, follow these steps:
- Rename the
.env.example
to.env
. - Replace the placeholder URL with the WebSocket URL you wish to consume.
- Rebuild the example with the
npm run build-dev
ornpm run build-prod
for the changes to take effect.
If you wish to include this functionality in your project, you will need to include the following steps, which are also demonstrated in the TypeScript example:
- Install
dotenv
via NPMnpm i dotenv --save-dev
. - Include
dotenv
in your webpack file and set your.env
file path usingpath:
:
require('dotenv').config({ path: './.env' });
- Include a plugin in your webpack file with the environment variable's name. For this example, the name will be set to
WEBSOCKET_URL
:
new webpack.DefinePlugin({
WEBSOCKET_URL: JSON.stringify((process.env.WEBSOCKET_URL !== undefined) ? process.env.WEBSOCKET_URL : '')
}),
- Create the
.env
file in the path you set in the previous step with the variable of your choice:
WEBSOCKET_URL=ws://example.com/your/ws
- Declare your environment variable where you instantiate your SPS frontend library:
declare var WEBSOCKET_URL: string;
- Make use of the
setTextSetting
method within theconfig
instance to set theTextParameters.SignallingServerUrl
to a variable that makes use ofWEBSOCKET_URL
:
let webSocketAddress = WEBSOCKET_URL;
if(webSocketAddress != ""){
config.setTextSetting(TextParameters.SignallingServerUrl, webSocketAddress)
}
Further customisation of UI elements like overlays or visual elements can also be achieved by utilising the Pixel Streaming Frontend UI and extending its types. For further information on how to utilise the Epic Games Pixel Streaming Frontend UI refer to the Pixel Streaming Frontend UI documentation.
This may be useful if you need to make modifications to the default SPS frontend and want to deploy it in your SPS installation.
- Build the
examples/typescript
frontend using the instructions above. - Navigate to the root of this repository.
docker build -t yourdockerhubaccount/my-custom-sps-frontend:latest -f dockerfiles/sps-frontend.dockerfile .