| title | Use JavaScript in extensions |
|---|
After creating a new extension, you need to define an action with a JS event to declare the library code.
In order to get the library code, you can copy the content of a bundled library for instance a UMD one. You can usually find bundled libraries in the node_modules folder of a JS project after the installation of the library with a package manager.
Bundled libraries have some extra code at the beginning and the end of the file to bundle the library. This code is not needed. Instead, the classes are added to the gdjs namespace like in the following code:
// Avoid to declare the library several times.
if (gdjs._myNewExtension) {
return;
}
// My library function and classes
const myPrivateFunction = () => {
// Some code here.
}
const myPublicFunction = () => {
// Some code here.
}
class MyPrivateClass {
// Some code here.
}
class MyPublicClass {
// Some code here.
}
// Add all public function and classes to `gdjs` namespace.
gdjs._myNewExtension = {
myPublicFunction,
MyPublicClass,
};!!! warning
Make sure never to use the `runtimeScene` given by the JS event when declaring a library because it is the scene at the declaration which is unlikely to be the same one when the code is called. Instead, the caller should pass `runtimeScene` as parameter.
This action must be called before the first scene is loaded in the onFirstSceneLoaded events function. When a behavior uses the library, it must also be called at the object creation in onCreated because instances in the scene editor are created before onFirstSceneLoaded is called.
When a new scene is loaded, you can initialize the attributes you need in the onSceneLoaded event function.
runtimeScene._myNewExtension = runtimeScene._myNewExtension || {
myAttribute: new gdjs._myNewExtension.MyPublicClass(),
};These 2 extensions instantiate a state on scenes:
- The Noise generator instantiates a manager that gives generators from their names.
- The Curved movement also instantiates a manager for curves.
When a new object instance is created, you can initialize the attributes you need in the onCreated event function.
behavior._myNewExtension = behavior._myNewExtension || {
myAttribute: new gdjs._myNewExtension.MyPublicClass(),
};These 2 extensions instantiate a state on behaviors:
- The Boids movement uses a state to keep track of Boids speed.
- The Object stack uses a state to keep track of the object in the stack.
Number, string and boolean parameters can be accessed with getArgument. Parameter names are case sensitive.
const angle = eventsFunctionContext.getArgument("Angle");For object parameters, getObjects must be used. It gives an Array of gdjs.RuntimeObject.
const players = eventsFunctionContext.getObjects("Player");
for (const player of players) {
}When you chose a specific type for the object in the parameter list, you need to declare the type in the code to get all the autocompletions. For instance, for sprite objects, you will add the following:
/** @type {Array<gdjs.SpriteRuntimeObject>} */
const players = eventsFunctionContext.getObjects("Player");You can find the list of all object types in the GDJS documentation page for RuntimeObject.
Resource parameters are strings containing the name of the resource. You can get the resource content from some ResourceManager.
For instance, to get an image for a 2D game you can do as follows:
const resourceName = eventsFunctionContext.getArgument("MyImage");
runtimeScene.getGame().getImageManager().getPIXITexture(resourceName);For 3D games, you can get a texture with this other method:
runtimeScene.getGame().getImageManager().getThreeTexture(resourceName);!!! warning
By default, resource names look like a relative path, but it should not be used as a path because it won't necessarily be a valid path (and it can be changed by users to anything).
After getting the events function parameter values, you can pass them to a JavaScript function.
gdjs._myNewExtension.doSomething(myParameter);runtimeScene._myNewExtension.myAttribute.doSomething(myParameter);These 2 extensions call functions on a state they created on scenes:
- The Noise generator
- The Curved movement
behavior._myNewExtension.myAttribute.doSomething(myParameter);These 2 extensions call functions on a state they created on behaviors:
- The Boids movement
- The Object stack
For expressions, you need to return a number or a string by setting returnValue.
eventsFunctionContext.returnValue = gdjs._myNewExtension.getSomeValue();For condition, you need to return a boolean by setting returnValue.
eventsFunctionContext.returnValue = gdjs._myNewExtension.isSomethingRight();In case you are writing your first custom behavior, please refer to the custom behavior page to learn more about them.
Behaviors parameter values are actually just a string of the behavior name. Each object instance has their own behavior instance so it avoids to pass an array for behaviors when they can be mapped from objects with object.getBehavior(behaviorName).
For actions and conditions of behaviors, the object parameter Object only contains one instance because GDevelop does the iteration on object instances. For other object parameters you still need to iterate on all instances.
const object = objects[0];
const behaviorName = eventsFunctionContext.getBehaviorName("Behavior");
const behavior = object.getBehavior(behaviorName);Behavior properties can be accessed from getters. The property name defined in the property editor is prefixed with _get. Property names are case sensitive.
const myPropertyValue = behavior._getMyProperty();Setters also exist, but you should not need them. Behaviors may have events functions to change its property values but it's easier to implement them with events. If you need to change property values from your JavaScript code, you probably should use JavaScript attributes instead and define expressions to let events access their values.
GDevelop use Pixi.js to render 2D and Three.js to render 3D. Some of these 2 libraries features are not exposed by GDevelop and you may want to do it by warping them into events-based objects.
Events-based objects are generated as classes that inherit either:
Custom objects usually rely on their child-objects to do the rendering. You may want to override the getRenderer method to use your own renderer.
For instance, these 3 extensions expose events-based objects:
- 3D particle emitter uses the three.quarks library
- 3D sprite uses the PlaneGeometry of Three.js
- 3D text uses the Troika Text for Three.js library
!!! note
Most of the previous section about events-based behaviors also applies to events-based objects.
Although GDevelop engine features can be used in JavaScript (learn more about it in the JavaScript events page). It's easier to use events for this.
Both JavasScript and events can be used in the same extension:
- Events allow to easily use GDevelop engine features
- JavaScript should be only used for code independent from GDevelop
JavaScript and events should only communicate through actions, conditions and expressions. JavaScript code should avoid at all cost to use event variables directly because it will likely result to spaghetti code. Variables can still be passed as events function parameters in case the extension needs to exchange a structure or an array with the events.
These 2 extensions use a JavaScript library but also use some of GDevelop engine features with events:
- The 3D object shake extension uses a noise library and implements with events a behavior that makes 3D objects shake.
- The Curved movement extension evaluates Bézier curves using JavaScript and handles movement logics with events.
Extensions can be implemented with events and JavaScript or a mix of both. Looking at existing extensions can help to understand the API and extension system.
This is a few instances of extensions that use JavaScript:
- The Noise generator extension uses a noise library and exposes its features through expressions, action and conditions.
- The 3D object shake extension uses the same noise library from the above extension but exposes a behavior that makes 3D objects shake.
- The Curved movement extension evaluates Bézier curves using JavaScript and handles movement logics with events.
- The Boids movement extension exposes a behavior to users and uses a R-Tree internally to quickly check neighbors.
- The Object stack extension exposes conditions that pick object instances according to their position in a stack.
- The Clipboard extension uses an asynchronous web API and implements fallbacks to Electron API or Cordova plugins.
Starting with GDevelop 5.5.222, you can also open the extension properties, and then add a JavaScript source file:
This source file will be:
- only imported if the extension is used in your game (for example, a scene uses an action or condition from the extension).
- imported as the same time as the files of the game engine or other extensions. It can either be set to be imported before the game engine files or after (but the order between files is not guaranteed). It works both for the preview and when the game is exported.
- no transpilation or changes are done on the file.
- the file will be added as a "JavaScript" resource in the resources editor.
!!! warning
Remember to make sure your extension is used by the game so that the file is included.
If you export your extension, this file *won't* be included. Consider this option as an experimental option to add custom JavaScript code to a project.




