tb-harmony-modern-ts
This repository is a project template that allows you to code in modern TypeScript (ES6) for ToonBoom Harmony.
Example script
This script prints all the nodes recursively (following node groups) in the scene using JavaScript generators:
// src/lib/console.ts
const console = { log: MessageLog.trace };
// src/scripts/generator.ts
import console from "../lib/console";
function* recursiveIterNodes(n: string): Generator<string> {
yield n;
if (node.isGroup(n)) {
for (let i = 0; i < node.numberOfSubNodes(n); i++) {
yield* recursiveIterNodes(node.subNode(n, i));
}
}
}
function main() {
const nodes = Array.from(recursiveIterNodes(node.root()));
for (const node of nodes) {
console.log(node);
}
}
main();
Why
You can script in two ways for ToonBoom Harmony: either with Python or QtScript (JavaScript).
QtScript (scripting engine part of the Qt framework) is an old JavaScript dialect that is based on the ECMAScript 3.0 standard, therefore it lacks features like modules, modern syntax, arrow functions, etc...
Today we have TypeScript which is a superset of JavaScript with syntax for types, ES modules, async/await. All those features provide better code organization, type checking and robustness.
Usage
This template was built in a script-centric workflow. All the .ts scripts in the src/scripts directory are entrypoints and built into the dist directory as .js bundles.
- Clone and install the dependencies:
❯ git clone https://git.autourdeminuit.com/autour_de_minuit/tb-harmony-modern-ts
❯ cd tb-harmony-modern-ts
❯ npm install
- Then create a new script in
src/scripts:
❯ touch src/scripts/arrow-function.ts
// src/scripts/arrow-function.ts
const hello = (name: string) => MessageLog.trace(`Hello, ${name}!`);
hello("Alice");
- And build it:
❯ npm run build # runs webpack
Then it's built as an IIFE and transpiled into QtScript compatible syntax:
// dist/arrow-function.js
/******/ (function () {
// webpackBootstrap
var hello = function hello(name) {
return MessageLog.trace("Hello, ".concat(name, "!"));
};
hello("Alice");
/******/
})();
Then you can run it by starting Harmony with the TOONBOOM_GLOBAL_SCRIPT_LOCATION env variable pointing at the dist folder where you cloned this repo.
For example you can also run this script from the command line in batch mode (in PowerShell):
❯ $env:TOONBOOM_GLOBAL_SCRIPT_LOCATION="tb-harmony-modern-ts/dist"
❯ &"path\to\HarmonyPremium.exe" -scene "scene.xstage" -batch -compile "dist/arrow-function.js"
# ...
# Loading script: tb-harmony-modern-ts\dist\arrow-function.js
# Hello, Alice!
How
Based on the above example, here is a diagram that shows the compilation/transpilation process (simplified):
TypeScript and type definitions
We can code in TypeScript but in order to use Harmony's QtScript API, we need type definitions (.d.ts files describing the types).
Luckily for us, Bryan Fordney made scripts to generate them: tba-types (Typescript definitions for Toon Boom Harmony and Storyboard Pro)
We can now type-check our code with the right classes and members accessible in the global QtScript scope. Those type definitions still have a few quirks but they can be improved through PRs!
ES6 syntax and polyfill
The JavaScript language specification is moving fast. What if you want to use the newest features but your runtime isn't as recent? Here comes Babel, it's a JavaScript compiler that allows us to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.
This is perfect because QtScript is like ES3 and we want to use ES6 features.
A key feature of Babel is that it integrates with core-js, providing polyfills for modern JavaScript features. For example QtScript don't have async/await but core-js can inject the Regenerator runtime to make it work.
Modules and imports
In Harmony's QtScript you can import code from another file in two ways:
include
include("module.js");
Which include the whole script into the current one, therefore polluting the current namespace.
exports
// function.js
exports.test = function test() {
MessageLog.trace("test");
};
// main.js
var module = require("./function.js");
module.test();
Which is a CommonJS "like" custom implementation from ToonBoom without the same semantics. It's also used to define ToonBoom packages by exporting a configure function from a configure.js file.
In today's modern JavaScript, the official standard package format is ECMAScript modules (or ESM/ES6 modules) with import/export.
Module bundling
We use WebPack as the module bundler. This is a common technique to organize and combine many files into a single JavaScript file. It resolves imports and optimize the bundles.
Since ToonBoom Harmony's QtScript module system is not that advanced, it allows us to use ES modules (and CommonJS too) to split code into separate files without having to manually import files.
This also means that we can use and import NPM packages with Harmony! (if they use a compatible standard library thought).
QtScript syntax fixes (custom Webpack plugin)
In QtScript, this syntax is not valid:
var obj = { for: 0 }; // Unexpected keyword "for" for literal property name
obj.for = 1; // Same here as property name
var re = /[^\s(/]/; // Syntax error, / is not escaped
// The correct syntax is /[^\s(\/]/
Most of the time, those expressions are injected from corejs polyfills. In order to patch this, I created a custom FindReplacePlugin for Webpack that does simple regex find/replace to fix those syntax errors.
Contributing
This repo is just a template with an opinionated config. If you would like to contribute to the config itself, please open an issue!
If it's related to the TypeScript type definitions, open an issue on the tba-types repo.
Acknowledgements
- OpenHarmony - The Toonboom Harmony Open Source DOM Library created by Mathieu Chaptel and Chris Fourney. This library is like PyMEL but for ToonBoom Harmony and a huge source of knowledge about the details of scripting in Harmony. 🙏
- tba-types - Typescript definitions for Toon Boom Harmony and Storyboard Pro created by Bryan Fordney. These are generated types scrapped from the ToonBoom documentation itself.
- core-js - Modular standard library for JavaScript. Includes polyfills for ECMAScript up to 2025, ECMAScript proposals and some cross-platform WHATWG / W3C features.

