Tutorial 1: JavaScript hello world
In this tutorial you build the smallest useful JavaScript plugin: a counter variable, a settings page, one action that bumps the counter, and a status bar item. You need only a text editor and a running Macro Grid server; there is nothing to build or compile.
The finished plugin lives in the repository as examples/hello-js (a copy of HelloJs/, kept identical by CI). Every code block below is taken from that folder.
Step 1: the folder and the manifest
Create a folder hello-js with a file plugin.json:
{
"id": "hellojs",
"name": "Hello (JavaScript example)",
"description": "A minimal JavaScript plugin: a counter variable, a settings page, one action and a status item.",
"author": "Deccoyi",
"homepage": "https://github.com/Deccoyi/macro-grid-plugin/tree/main/HelloJs",
"version": "0.1.2",
"minMacroGrid": "1.0.0",
"sdkVersion": "^0.4.0",
"minServerVersion": "0.3.2",
"entry": "index.js",
"kind": "js",
"permissions": ["variables", "actions"]
}idmust be unique and stable. Variable names and action types must start with<id>.(herehellojs.).kindisjs, andentryis the script to run.permissionslists what the script needs.variableslets it publish variables,actionslets it register actions. The user has to approve exactly this list before the script runs.minMacroGridsays the oldest Macro Grid this plugin runs on (see Compatibility).
Step 2: a variable
Create index.js next to it. The script runs in a sandbox and reaches the server only through the global host object. Start with a counter variable:
let count = 0;
host.variables.describe([
{ name: 'hellojs.count', description: 'How many times the counter was bumped', example: '3', category: 'Hello' },
]);
host.variables.set('hellojs.count', count);host.variables.describe lists the variable in the editor's variable picker so users do not have to guess names, and host.variables.set publishes its first value. Any widget can now show it in its text as Count: {hellojs.count}.
Step 3: a settings page
host.settings.page([
{ key: 'step', label: 'Step', kind: 'Number', default: 1, min: 1, max: 100 },
]);host.settings.page adds a settings form to the Plugins window from a list of fields. The values are stored in a settings.json in the plugin's folder and read back with host.settings.get().
Step 4: an action
host.registerAction({
type: 'hellojs.bump',
name: 'Bump the counter',
category: 'Hello',
description: 'Adds the configured step to the hellojs.count variable.',
icon: 'plus',
fields: [
{ key: 'times', label: 'Times', kind: 'Number', default: 1, min: 1, max: 10 },
],
run(context, settings) {
const step = host.settings.get().step || 1;
count += step * (settings.times || 1);
host.variables.set('hellojs.count', count);
},
});host.registerAction adds an action to the editor's action picker. fields describes the action's own form (here a Times number); run is called when the action fires, with the values of that form as settings. Here it adds step * times to the counter and publishes the new value.
Register at the top level
Actions, the settings page and variable descriptions must be registered while the script first runs. Registrations made later, from a callback, are ignored. Variables can be set at any time.
Step 5: a status item
// Timers need no permission. The shortest allowed interval is 100 ms.
host.every(5000, () => {
host.status('counter', 'Count ' + count, 'Ok');
});host.every(ms, fn) repeats a function (the shortest interval is 100 ms) and host.status(id, text, level) updates an entry you own in the editor's status bar. Timers need no permission.
The whole script:
// A small example of a JavaScript plugin. It publishes a counter variable that any widget can show
// ("Count: {hellojs.count}") and adds one action that bumps it. Everything a plugin can do goes through
// the global `host` object; there is no other access to the server.
// #region variable
let count = 0;
host.variables.describe([
{ name: 'hellojs.count', description: 'How many times the counter was bumped', example: '3', category: 'Hello' },
]);
host.variables.set('hellojs.count', count);
// #endregion variable
// #region settings
host.settings.page([
{ key: 'step', label: 'Step', kind: 'Number', default: 1, min: 1, max: 100 },
]);
// #endregion settings
// #region action
host.registerAction({
type: 'hellojs.bump',
name: 'Bump the counter',
category: 'Hello',
description: 'Adds the configured step to the hellojs.count variable.',
icon: 'plus',
fields: [
{ key: 'times', label: 'Times', kind: 'Number', default: 1, min: 1, max: 10 },
],
run(context, settings) {
const step = host.settings.get().step || 1;
count += step * (settings.times || 1);
host.variables.set('hellojs.count', count);
},
});
// #endregion action
// #region status
// Timers need no permission. The shortest allowed interval is 100 ms.
host.every(5000, () => {
host.status('counter', 'Count ' + count, 'Ok');
});
// #endregion statusStep 6: install it
- In the editor open Plugins, Manage Plugins... and choose Install from Folder...
- Pick the
hello-jsfolder. It is copied to%AppData%\MacroGrid\plugins\hellojs\. - The plugin shows as Needs approval. Read the permission list and approve it. The plugin starts.
Step 7: use it
- Add a button to a page. Set its text to
Count: {hellojs.count}(the variable is also in the{...}picker, category Hello). - Bind an action to its press event: pick Bump the counter (category Hello) and set Times.
- Save, open the deck and press the button. The text counts up.
- Open the plugin's gear button in the Plugins window and change Step: each press now adds
step * times. - Look at the right of the status bar:
Count <n>updates every five seconds.
Step 8: change it and reload
Edit the script and try again without restarting the server. There are two ways:
- Change your source folder and use Install from Folder... again. A folder with the same
idreplaces the installed plugin, and the plugin's ownsettings.jsonis kept. - Or edit the installed copy in
%AppData%\MacroGrid\plugins\hellojs\index.jsand click Reload in the Plugins window.
If the script throws while it first runs, the plugin shows as Error with the message under its name; fix it and reload. See Debugging and logs.
What to try next
- Read the JavaScript host API reference, for example
host.http.getto poll a local service (needs anhttp:<host>:<port>permission). - Continue with Tutorial 2 to format your variable in widget text.
