# Creating a Simple Controller

### Example Project <a href="#example-project" id="example-project"></a>

Unzip this template project exampleTemplate into a project development folder of your choosing.

{% file src="/files/leVYGrqRooKxYvKeIcKT" %}

Once unzipped, explore the project folders…

At the top level is the “Example App” folder and a batch file for installing the app (we will use this later.)

<div align="center"><figure><img src="/files/XxS0DW1qtpeltI2wyOJR" alt=""><figcaption></figcaption></figure></div>

Click on the Example App folder.

<div align="center"><figure><img src="/files/IeNdJ2qQwDlaZgUUeH8z" alt=""><figcaption></figcaption></figure></div>

`common` includes two JavaScript files necessary for communicating with the API. These must be installed with the app.

`exampleSRC` carries the source for this example.

`example.xml` defines this controller. Captivate reads this to set things up, so you will need to create one of these for each Controller you write.

### Example.xml <a href="#examplexml" id="examplexml"></a>

Let’s start by looking in example.xml:

```xml
<inputBehavior
  name="Example App: Date and Time"
  url="exampleSrc/exampleApp.html"
  iconOn="exampleSrc/alien.png"
  UIGroups="General">
  <variable name="Date" type="text" />
  <variable name="Time" type="text" />
</inputBehavior>
```

`name`: This sets the name of the controller. Note that the part before the colon, “Example App,” must match the name of the parent folder. The part after the colon will be used in the Captivate UI menu, in this case, “Date and Time.” The whole string that identifies this input, must be unique among all controller inputs and should be used in subsequent API calls.

`url`: This provides the location of the actual web page to load. If this were running off a cloud server, it would provide the full URL. In this case, it provides a relative path.

`iconOn`: This is an optional icon file used to display the icon for this controller in the Captivate title/layer list.

Next, this file lists all the variables that this input will provide to any title it is controlling. In this case, there are two variables, “Date” and “Time.” Both are “text” variables, meaning they provide text values.

### ExampleApp.html <a href="#exampleapphtml" id="exampleapphtml"></a>

Now, go into the `examplesSrc` folder where you will find the `aliens.png` and the `exampleApp.html` file.

Open `exampleApp.html` in your code editor:

```html
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script type="text/javascript" src="../common/js/qwebchannel.js"></script>
    <script type="text/javascript" src="../common/js/servicehandler.js"></script>
    <script type="text/javascript">
      window.onload = function () {
        // Initiate the server connection.
        ServiceHandler.init();
        // Retrieve the name of this input.
        var inputName = ServiceHandler.inputName;

        // We should handle error conditions, such as network loss or something else unexpected.
        ServiceHandler.onclose = function () {
          console.warn('ServiceHandler disconnected');
        };

        ServiceHandler.onerror = function (error) {
          console.error('ServiceHandler error', error);
        };

        // This is our callback when the server is connected and we're ready to access the APIs.
        ServiceHandler.onready = function () {
          // Set up responses to the three button clicks.

          // When the user clicks on the Play In button, set the time and date variables and fly the title in.
          document.getElementById('schedulePlayIn').onclick = function () {
            // Create a json object for variables to set.
            var variables = {};
            // Set the current time and date.
            var timeNow = new Date();
            variables['Time'] = timeNow.toLocaleTimeString();
            variables['Date'] = timeNow.toLocaleDateString();
            // Send the AnimateIn action with this input as the sender, and the new variable settings.
            ServiceHandler.scheduler.scheduleAction('animateIn', ServiceHandler.inputName, '', variables);
          };

          // When the user clicks on the Update button, update with the current time and date.
          document.getElementById('scheduleUpdate').onclick = function () {
            // Create a json object for variables to set.
            var variables = {};
            // Set the current time and date.
            var timeNow = new Date();
            variables['Time'] = timeNow.toLocaleTimeString();
            variables['Date'] = timeNow.toLocaleDateString();
            // Send the update action with this input as the sender, and the new variable settings.
            ServiceHandler.scheduler.scheduleAction('update', ServiceHandler.inputName, '', variables);
          };

          // When the user clicks on the Play Out button, fly the title out.
          document.getElementById('schedulePlayOut').onclick = function () {
            // Send the AnimateIn action with this input as the sender, and no variables.
            ServiceHandler.scheduler.scheduleAction('animateOut', ServiceHandler.inputName, '', {});
          };

          console.info('ServiceHandler connected, ready to send/receive messages!');
        };
      };

      window.onbeforeunload = function () {
        ServiceHandler.scheduler.pageClosed(inputName);
      };
    </script>
  </head>
  <body>
    <div class="w3-container w3-small ">
      <h4>Date and Time</h4>
      <p>Click on buttons to trigger actions:</p>
      <input type="submit" id="schedulePlayIn" value="Play In" />
      <input type="submit" id="scheduleUpdate" value="Update" />
      <input type="submit" id="schedulePlayOut" value="Play Out" />
    </div>
  </body>
</html>
```

As you can see, this is a minimal application.

<figure><img src="/files/dgUcUYLwTVcbeoRMTxNz" alt=""><figcaption></figcaption></figure>

It has three buttons which will play a title in, update its values, and play it out.

Let’s see what each of these does.

Start by looking at the code for the first button:

```javascript
// When the user clicks on the Play In button, set the time and date variables and fly the title in.
document.getElementById('schedulePlayIn').onclick = function () {
  // Create a json object for variables to set.
  var variables = {};
  // Set the current time and date.
  var timeNow = new Date();
  variables['Time'] = timeNow.toLocaleTimeString();
  variables['Date'] = timeNow.toLocaleDateString();
  // Send the AnimateIn action with this input as the sender, and the new variable settings.
  ServiceHandler.scheduler.scheduleAction('animateIn', ServiceHandler.inputName, '', variables);
};
```

This creates a JavaScript object where each key is the name of an input variable and each value assigned to it is the string value for that Variable.

Then, it calls the `scheduleAction` API. [`scheduleAction`](/api-examples/sample-controllers-tour/01-schedule-action.md) is the core API function used to schedule “actions” on a title. Actions are special commands that manage title playback.

The parameters are:

| Parameter   | Description                                                                                                                                                          |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`    | The action to take, for example ‘render’ to prepare a title or ‘update’ to update the title with new values.                                                         |
| `inputName` | Name of this Controller’s Input. If provided, the action applies to all Titles connected to this Input; if omitted, it applies to all Titles in the project.         |
| `titleId`   | The ID of a specific Title. If an Input is connected to multiple Titles, use this to specify which one to update (see the API on `scheduleCommand` to get Title IDs) |
| `variables` | The JavaScript object with any variable values to assign.                                                                                                            |

Take a look at the code for the other two buttons. It’s very similar, with the primary difference being the action itself.

> **Note**: The function calling `animateOut` doesn’t modify the variables, and instead sends an empty object to the scheduler (`{}`). Captivate will only modify variable values when it receives new data for them, so you only need to send variable values when data in Captivate should change.

Okay, now let’s install this and run it!

### Installing `ExampleApp.html` <a href="#installing-exampleapphtml" id="installing-exampleapphtml"></a>

Go back up to the top level and, if you are on Windows, simply double-click on copyfiles.bat. This script copies all XML, HTML and other related files in a sub-folder under `C:\Program Files\NewBlueFX\Titler Content\Resources\Service Handlers\HTML`

If on a Mac, you can drag and drop the entire Example App folder to `/Library/Application Support/NewBlueFX/Titler Content/Resources/Service Handlers/HTML`

### Run In Captivate <a href="#run-in-captivate" id="run-in-captivate"></a>

Start Captivate. If it is currently running, you must quit it and restart. This is because it only reads the XML definition file once, on startup.

Once it is running, place any title which has two or more text variables in the Title/Layer list.

Then, in the data controllers column of that title, click to select your new input from the popup menu.

<div align="center"><figure><img src="/files/FANm5KBpe7WJrYkYUKM3" alt=""><figcaption></figcaption></figure></div>

Once selected, it should show up as the input with the little green alien icon to the left of it.

Next, assign the `Date` and `Time` variables to your title in the preview pane.

<figure><img src="/files/ZEYixV3GlEW34sPbC83k" alt=""><figcaption></figcaption></figure>

Simply drag and drop each to the desired text fields in the title.

Now it is ready for testing. Try the three buttons.

### Debugging <a href="#debugging" id="debugging"></a>

Next, directly debug the app right here in the browser. Right mouse click to access the DevTools option.

<figure><img src="/files/1QFRBopBIuH9S8aXWDvZ" alt=""><figcaption></figcaption></figure>

This opens a Chromium debugger window.

Choose the sources tab and select the source file in the file view on the left.

<figure><img src="/files/l2t5bkHyyYaJPyfcQoYr" alt=""><figcaption></figcaption></figure>

Now you are ready to debug.

If you click to the left of a line number, it inserts a break point.

<figure><img src="/files/BrvvoivePImzEVouThY2" alt=""><figcaption></figcaption></figure>

Now, click on the button and the debugger will stop at this break point. You can now step through the code and see how it works.

If you make changes to the source code, it’s easy to update the code live in Captivate. Just copy the files in again and then right mouse click in the browser and choose reload.

<figure><img src="/files/Rcxe6AOONsexgIWw7wqL" alt=""><figcaption></figcaption></figure>

Now that you are up and running, go to [Sample Controllers Tour](/api-examples/sample-controllers-tour.md) and dive deeper into the programming samples. Be sure to check out the [JSON Command Tester](/api-examples/json-command-tester.md), which offers a quick way to discover and explore over two dozen API commands.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developers.newbluefx.com/api-examples/creating-a-simple-controller.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
