In this article we'll go over how to write expressions libraries, (.jsx
) files, in TypeScript, with automatic refresh, using Rollup.js.
This means you can write expressions with the full benefits of:
- Bundling from multiple files at build time
- Type checking
- Auto-completion
- Testing
js
// src/index.test.tsimport { welcome } from "./index";test("returns correct welcome string", () => {expect(welcome("test")).toEqual("Welcome test!");});
All while working in working in VS Code, that will re-compile and update in After Effects on save.
This article assumes you're familiar with tools such as Git, GitHub, NPM.
If you're not sure what these are, feel free to read on but you may encounter issues.
You can also watch our tutorial on the topic below:
Quick setup
- Create a new project using
create-expression-lib
bash
npx create-expression-lib project-name --install
And then navigate into the project folder via:
bash
cd project-name
- Edit the
/src
files
Any code exported from src/index.ts
file will be output to dist/index.jsx
as a After Effects compatible .jsx
file.
- Run rollup in watch mode
bash
npm run watch
This will re-compile your files into After Effects compatible .jsx
files every time you save.
- Import the file into After Effects
You can then import the output .jsx
file into After Effects, and use it in your expressions, for example.
js
const libraryCode = footage("index.jsx").sourceData;libraryCode.someFunction();
After Effects will reload the .jsx
file when it's recompiled, so you'll see the result of your code every time you save your source file.
Using the After Effects API
Since you're writing expressions outside of After Effects, native attributes and native methods such as thisComp
, linear()
and wiggle()
aren't defined when you're writing the code.
To add type safety and auto completion for After Effects variables and functions, this setup uses the package expression-globals-typescript.
This package mocks the After Effects API in TypeScript, so you can write expressions outside of an After Effects environment.
Classes
To create layers, compositions and properties, you can use the classes exported from the library. For example:
ts
import { Comp, Layer } from "expression-globals-typescript";const thisComp = new Comp();const thisLayer = new Layer();
To create properties (such as position or scale), you can use the Property
class.
ts
import { Property, Vector } from "expression-globals-typescript";const thisProperty = new Property<Vector>([0, 100]);
The Property
constructor takes a value to set as the property value, and a type (<>
) to set as the type for the property.
After Effects Types
You can import After Effect's specific types such as Color
and Vector
from the package to properly type your expressions.
typescript
import { Color, Vector } from "expression-globals-typescript";const textColor: Color = [1, 1, 1, 1];const textPosition: Vector = [950, 540];
To see all the Types and Base Objects available, see the expression-globals-typescript source code.
How it works
- expression-globals-typescript allows you to use the Expressions API outside of After Effects
- Rollup.js watches the source files, bundles them into one, and runs the TypeScript compiler as well as:
- rollup-plugin-ae-jsx Transforms the output code into After Effects compatible JSON (
.jsx
) files
Creating releases
To distribute the output (.jsx
) file via GitHub releases, you can run the release
command:
bash
npm run release
This will create a new release on GitHub using the GitHub CLI, attaching the output dist
file to the release.
You will need to have the GitHub CLI installed on your machine for this to work.
There's two settings in your package.json
that affect the release:
- The release version comes from the
"version"
- You can set which file to attach to the release in the
release
script, which isdist/index.jsx
by default
The "version"
is also added to the output .jsx
file at build time.
Testing
Expressions Library Template comes configured with Jest and ts-jest. This enables you to write tests for your expressions that will run on each save, giving you confidence that any code changes haven't broken your expression library.
For more details on writing tests with Jest, see the Jest docs.
You can write tests in the src/index.test.ts
file, importing the code you want to test from index.ts
. For example:
js
// src/index.test.tsimport { welcome } from "./index";test("returns correct welcome string", () => {expect(welcome("test")).toEqual("Welcome test!");});
And then run the test suite in watch mode via the command:
bash
npm run test
For a more detailed example of writing tests for expressions, you can view the tests for our eKeys library.
Splitting expressions across files
To split your expression into multiple files, all you need to do is:
- Export from one file
typescript
// anotherFile.tsconst someVariable: string = "this is in another file";export { someVariable };
- Import and export from the
index
file
typescript
// index.tsimport { someVariable } from "./anotherFile";const localVariable: number = 2;export { someVariable, localVariable };
They will then be bundled into the output file at build time.
Blog