- 09 Sep 2024
- 8 Minutes to read
- Print
- DarkLight
- PDF
Script Engine
- Updated on 09 Sep 2024
- 8 Minutes to read
- Print
- DarkLight
- PDF
The Script Engine is a powerful feature that allows you to create more complex scenes controlled by code (JavaScript). Almost all features and functions in Composer can be used via the Script Engine, and you can access all inputs, scenes, targets, and connectors.
Using the Script Engine, you can create logic that controls your content based on internal and external information, game events, date/time, and much more. Below are a few examples:
- Start/stop playback of media
- Hide/show layers
- Animate layer opacity, position, or rotation
- Read object properties
- Take action based on date, time, frame count, or external data
- Start/stop targets
- Trigger a connector
- Call a batch command
- Execute a target command
- Switch layer source
The Script Engine is designed to alter the project assets/setup, execute commands, and trigger connectors. It is not intended for building projects or replacing the desktop UI.
In the current version, R2 2024, the Script Engine is considered an experimental feature that might contain bugs or render unexpected results. However, at the time of writing, there are no known bugs.
Use the Script Engine with caution.
RealSprint does not provide support for user-created scripts.
Getting started
Using the Script Engine requires knowledge of JavaScript and an understanding of how Composer works. It should be seen as an advanced feature and is only recommended if you are familiar with JavaScript, have knowledge of software development, and have a deep understanding of Composer.
To start, follow these steps:
- Enable the Scripting Engine in Settings
- Save your project (if not yet saved)
- Add a script to your project using the Script Engine/Create Script menu item.
- Save and reload your project.
- Use the Script Engine/Edit Script menu item to edit the script. This menu will use the system's default editor for Javascript files (.js). If you don’t have an editor, we recommend using Microsoft Visual Code.
Events
The Scripting Engine has three main functions where you add your code:
- OnProjectInit()
This method is called when the project is loaded and initialized. This is where you initialize your variables and setup your init state. - OnRenderFrame()
This method is called on every frame rendered by Composer. - OnProjectStop()
This method is called when the project stops (unloads)
Global variables can be declared and shared across the different functions. A complete code sample is further down this page.
Activating the Script Engine
By default, the Script Engine is disabled, but you can easily activate it in Settings:
- Enable Script Engine - enables or disables the engine
- Enable calling script functions from API: if enabled, script functions can be called from the HTTP API.
- Enable auto-reload of script - if this option is enabled, Composer will reload the script if the script is modified on disk.
- The script file must be located in the same folder as the project file, and use the .js extension.
Your first script
Below is an example of a very simple script:
///Required section---------------------------------------------
//Import namespaces
var VindralEngine = importNamespace('VindralEngine');
var Scene = importNamespace('VindralEngine.Compositing.Scene');
var VindralLogLibrary = importNamespace('VindralLogLibrary');
//Declarations that make it smoother to write code
var Project = VindralEngine.Project.RunningInstance;
var Animator = VindralEngine.Animator;
var Logger = VindralLogLibrary.Logger;
//End of required section---------------------------------------
//Declare global variables
let frameCount = 0;
//The OnProjectInit function will be executed at the project start
function OnProjectInit()
{
Logger.Debug('This is a debug message from the ScriptEngine of Composer, and the OnProjectInit() function');
}
//The OnRenderFrame function will be executed at every frame
function OnRenderFrame()
{
//Do some stuff every frame
frameCount=frameCount+1;
//On every 300:th frame, log the current frame number
if (frameCount % 300==0)
Logger.Debug('FramesProcessed: ' + frameCount);
}
//The OnProjectStop function will be executed then the project stops.
function OnProjectStop()
{
Logger.Debug('OnProjectStop called by ScriptEngine');
}
Debugging
Debugging your scripts is currently limited to using the logger feature, which can output debug information and track runtime errors. There is currently no support for breakpoints or inspectors.
Security
By default, the scripting engine is disabled, and scripts can only be executed from the same folder as the project file.
Performance
Script performance is presented in the lower right corner of the UI:
Fetching large Composer objects such as a Scene may be very costly. Carefully study the Execution time and avoid code that renders a long execution time.
Accessing scripts from the API
Executing JS functions from the HTTP API is disabled by default, but you can enable execution using Settings. When enabled, you can execute the JS function using the /api/scriptengine/execute function.
Example:
http://localhost:44433/api/scriptengine/execute?function=EnableAudioPreview
function EnableAudioPreview()
{
Project.EnableAudioPreview();
return ‘Audio preview enabled’;
}
You can also pass parameters to a JS function.
Example:
http://localhost:44433/api/scriptengine/execute?function=MyFunction¶meter=Hello
function MyFunction(string message)
{
return ‘You called MyFunction with the parameter’+message;
}
Passing more than one parameter is not currently supported. You can pass them as in a JSON object if more than one parameter is needed.
Accessing connectors from scripts
Connectors defined in Composer can be triggered from the Script Engine.
Example:
triggered=Project.TriggerConnectorByName('MyTrigger');
Limitations
By default, scripts have the following limitations:
- Max memory allocation: 4Mb
- Max number of lines executed: 10.000
- Max execution time: 400ms
If any of these limitations are overrun, the Script Engine will render an error and stop.
Code Examples
The Script Demo project in the tutorials menu can be a good starting point.
Script support functions
Composer has several functions designed as support functions for the Script Engine. These functions provide fast and easy access to commonly used tasks.
Return type | Name and parameters |
---|---|
Scene | GetSceneByName (string name) |
Layer | GetLayerForScene (Scene scene, string name) |
Layer | GetLayerByName (string sceneName, string layerName) |
Object | GetInputByName (string name) |
Object | GetTargetByName (string sceneName, string targetName) |
LayerTransform | GetLayerTransformByName (String sceneName, string layerName) |
Object | GetLayerOperatorByName (String sceneName, string layerName, string operatorName) |
bool | SetObjectProperty (object op, string propertyName, string value) |
Object | GetObjectProperty (object op, string propertyName) |
LayerTransform | GetLayerTransformByName (Scene scene, string name) |
MediaFileInput | GetMovieInputByName (string name) |
bool | ShowLayerByName (string sceneName, string layerName) |
bool | HideLayerByName (string sceneName, string layerName) |
bool | SetLayerOpacityByName (string sceneName, string layerName, int opacity) |
long | GetLastScriptEngineExecutionTimeMs () |
long | GetLastScriptEngineExecutionTimeTicks () |
bool | TriggerConnectorByName (string name) |
bool | StartMediaPlayBack (string name) |
bool | StopMediaPlayBack (string name) |
bool | SetActiveScenePreview(string name) This method will change the active scene preview. Desktop version only. |
void | EnableAudioPreview () This method will enable audio preview in the Desktop version of Composer. |
object | GetReplayOperatorByName (String sceneName, string layerName, string operatorName, out DateTime frameStoreStartTime, out DateTime frameStoreStopTime, out int numberOfFramesInStorage, out ReplayOperator.ReplayOperatorState playbackState) |
bool | StartReplayOperatorByName (String sceneName, string layerName, string operatorName, DateTime startDateTime, DateTime stopDateTime) |
bool | GetReplayOperatorPlaybackStoppedByName (String sceneName, string layerName, string operatorName) |
bool | CallBatchCommand(String Command, String batchName) Valid commands: SHOWLAYER, HIDELAYER and SHOWLAYERSOLO. Batch commands allow you to alter multiple layers in a single “batch” command. This can be useful when showing or hiding numerous layers in a single or multiple scenes. |
bool | ExecuteTargetCommand(String sceneName, string targetName, string commandName) Available commands: BlackMagicCaptureV3: StartCommand, StopCommand |
bool | SwitchLayerSource(string sceneName, string layerName, string sourceName) |
bool | SetLayerAudioLevelByName(string sceneName, string layerName, int volume). Valid volume values range from 0 (silent) to 100. |
Animator class
The Animator class supports animating layertransform properties, including position, anchor point, scale, opacity, and rotation.
Layertransform properties exist on all scene layers within Composer.
header | header |
---|---|
Guid | AddLayerTransformationItem(string sceneName, string layerName, AnimateTransform type, int durationMs, float startValue, float stopValue, string cData, AnimateEasing mode=AnimateEasing.EaseInEaseOut, AnimateOptions options=AnimateOptions.None) |
The cData parameter is currently not used/implemented.
The AnimateEasing and AnimateOptions parameters are optional.
The example below will animate the layer ‘Scene PGM’ found in the scene ‘Scene PGM with replay’. It will animate the opacity over a period of 1000ms, starting at a value of 30 and ending at 100. The animation will be smoothed using the AnimateEasing option EasiInEaseOut. No additional options are provided.
Project.Animator.AddLayerTransformationItem('Scene PGM with replay', 'Scene PGM', Animator.AnimateTransform.Opacity, 1000, 30, 100, 'Stuff with Opacity', Animator.AnimateEasing.EaseInEaseOut, Animator.AnimateOptions.None);
The example below will animate the x position of the layer ‘Logo’ found in the scene ‘Output scene’. In this case, the initial x position is the same as the current position. The end position is 200. The animation duration is 100 ms.:
Project.Animator.AddLayerTransformationItem('Output scene', 'Logo', Animator.AnimateTransform.PositionX, 100, 0, 200, '', Animator.AnimateEasing.EaseInEaseOut, Animator.AnimateOptions.UseCurrentValueAsInitialValue);
The AddLayerTransformationItem uses the following three enum parameters:
AnimateTransform enum
public enum AnimateTransform
{
PositionX,
PositionY,
ScaleX,
ScaleY,
AnchorPointX,
AnchorPointY,
Rotation,
Opacity
}
AnimateEasing enum
public enum AnimateEasing
{
Linear,
EaseInEaseOut
}
AnimationOptions
public enum AnimateOptions
{
None,
UseCurrentValueAsInitialValue
}
Internals
The Scripting Engine is based on https://github.com/sebastienros/jint
FAQ
Can I access/execute scripts using the API?
Yes, you can. Just ensure the Enable calling script functions from API are enabled in settings.
Example:
HTTP request: http://localhost:44433/api/scriptengine/execute?function=MyFunction¶meter=Hello
Script:
function MyFunction(message)
{
return ‘You called MyFunction with the parameter’+message;
}
Response:
You called MyFunction with the parameter Hello
How do I start the playback of a video clip?
Example:
//Get a reference to the input LogoAnimation.mov
var mediaInput=Project.GetMovieInputByName("LogoAnimation.mov");
if ((mediaInput!=null) && (mediaInput.PlayCommand.CanExecute))
mediaInput.PlayCommand.Execute();
How do I get the current frame from a video clip?
Example:
//Get a reference to the input LogoAnimation.mov
var mediaInput=Project.GetMovieInputByName("LogoAnimation.mov");
//Get the current playback frame
var currentFrame=mediaInput.VideoFrameIndex;
How do I trigger a connector that I have defined in Composer?
Example:
//If the trigger is found, the return value will be true
triggered=Project.TriggerConnectorByName('MyTrigger');
How do I load an image into an existing input?
Example:
myUri=System.Uri('C:\\Program Files\\RealSprint AB\\Vindral Composer\\Media\\Images\\fishingplace.jpeg', System.UriKind.Absolute);
myInput=Project.GetInputByName('My still image');
myInput.SourceUrl=myUri;
Can I start or stop targets in Composer?
Example:
//Start recording
target=Project.GetTargetByName('Scene','FileTarget #1');
if ((target!=null) && (target.StartCommand.CanExecute))
{
target.StartCommand.Execute();
Logger.Debug('Starting recording');
}
How do I retrieve the name and file path to the current running project?
Example:
Logger.Debug('Current project: '+Project.RunningProjectFileName);
How do I retrieve the number of errors and warnings?
Example:
Logger.Debug('Number of errors: '+Project.NumErrorsReported+', Warnings: '+Project.NumWarningsReported);
How can I change the settings for an operator?
Example:
histogramOperator = Project.GetLayerOperatorByName('Scene Tracker', 'My video clip', 'Histogram Operator');
if (histogramOperator != null) {
//Get the value TemporalQualified (boolean)
valueBool = Project.GetObjectProperty(histogramOperator, 'TemporalQualified');
//Do something with the value
}
How can I get a reference to a scene layer and set a property on that layer?
Example:
layer = Project.GetLayerByName('Scene PGM', 'TextBallInPocket')
if (layer != null)
layer.IsVisible = false;
Can I fetch a property from an operator? For example, the Histogram Operator?
Example:
histogramOperator = Project.GetLayerOperatorByName('Scene Tracker', 'Scene Masks', 'Histogram Operator');
if (histogramOperator != null) {
value = Project.GetObjectProperty(histogramOperator, 'TemporalQualified');
//Do something based on value
}
When is the OnRenderFrame() method executed?
At the beginning of each frame, before Composer renders the content.
Can I write a text file to disk? I need to store some values on disk.
Yes, you can. Below is an example:
var file = new System.IO.StreamWriter('my-data-file.txt');
file.WriteLine('Hello World !');
file.Dispose();
Can I access bitmap data (pixels) using the scripting engine?
No. JavaScript is too slow for processing bitmap data in real-time. And, there is currently no way of fetching a bitmap from Composer in JavaScript.
Can I use the Script Engine to create a web page shown in Composer?
No. The Script Engine can only interact with Composer properties, methods, and your project content.
Can I write my operators using the scripting engine?
No. Extending Composer requires access to the Composer SDK.
What happens if a project uses a script, but the script does not exist?
There will be an error during load, but the project will start anyway.
What happens if there is an error in the script?
There will be an error, and the script engine will stop.
What happens if the script takes too long to execute?
There will be an error, and the script engine will stop.
Do you provide technical support for JavaScript-related questions?
No.
Does the Script Engine work in the runtime version, including Linux?
Yes.
Can I use the Script Engine to use JavaScript code found on external web pages?
No.
Is the Script Engine running on multiple threads?
No, it is a single-threaded engine running on the same thread as the main Render thread in Composer.