Skip to main content

Lesson 01 — Environment Setup & Execution Model

Affinity SDK scripts are JavaScript files that run directly inside the Affinity application — not in a browser, not in Node.js, but embedded in the same process as the program itself. This lesson explains exactly how that works: how scripts are loaded and executed, how you access SDK modules with require(), and what constraints the environment places on you.

Understanding the execution model before writing a single line of code will save you hours of confusion. The runtime (Affinity's built-in JavaScript engine) has no fetch, no window, no process, and no file access outside the Desktop. Knowing these boundaries upfront means you will never waste time debugging something that simply cannot work in this environment.

What this lesson covers​

  • How Affinity SDK scripts execute
  • The require() module system
  • console.log() as your output channel
  • File system access constraints
  • The app singleton — version info, document access, dialog helpers

The execution model​

Affinity SDK scripts are synchronous JavaScript running inside the Affinity application process.

Key differences from Node.js or browser JS:

FeatureAffinity SDKNode.js
Module importsrequire('/module.js')require('./module') or ESM
Package managerNone — built-in modules onlynpm
Outputconsole.log() → Script consolestdout
Return valuesScripts return nothingFunctions return values
File accessDesktop + granted foldersAny path
Networkrequire('/network.js')HttpRequest, RequestMethod

The module system​

All imports use a leading /. This is the SDK's internal registry — not the file system.

'use strict';
// Correct
const { Document } = require('/document.js');
const { app } = require('/application.js');
const { RGBA8 } = require('/colours.js');

// Wrong — will throw
const { Document } = require('./document.js'); // no relative paths
const { Document } = require('document.js'); // no bare specifiers

console.log() — your only output​

Scripts produce no visible return value. Everything you want to inspect must be logged.

// Snippet
console.log('simple string');
console.log('label:', someValue);
console.log('multiple:', a, b, c);
console.assert(someCondition, 'message if false');

View output in the Script console panel in Affinity, below the editor.


File system access​

The SDK can read/write files on the Desktop and in folders you explicitly grant access to. Any other path returns PERMISSION_DENIED.

'use strict';
const { app } = require('/application.js');

// Always use this to get the Desktop path — don't hardcode it
const desktop = app.userDesktopPath;
console.log('Desktop:', desktop);
// macOS: /Users/yourname/Desktop
// Windows: C:\Users\yourname\Desktop

Application API​

The /application module exposes the Application class (app singleton) for app-wide queries and actions — version info, document listing, dialog helpers, and settings.

App info​

'use strict';
const { Application } = require('/application.js');

console.log('Version: ' + Application.version);
console.log('Build: ' + Application.buildVersion);
console.log('Platform: ' + Application.platformName);
console.log('Major: ' + Application.majorVersion);
console.log('Minor: ' + Application.minorVersion);
console.log('Revision: ' + Application.revisionVersion);
console.log('Product: ' + Application.productFullName);
console.log('Short: ' + Application.productShortName);
console.log('Copyright:' + Application.productCopyrightMessage);
console.log('Compile: ' + Application.compileDate);
console.log('Args: ' + Application.argC + ' ' + Application.args.join(', '));

Document access​

// Snippet — assumes Application and Document are available
const { Application } = require('/application.js');
const { Document } = require('/document.js');

const all = Application.documents.all; // all open documents
const current = Application.documents.current; // same as Document.current

// Open a file from the Desktop
const doc = Application.documents.load(app.userDesktopPath + '/my-file.afdesign');

Dialog helpers​

// Snippet — assumes Application is available
const { Application } = require('/application.js');

Application.alert('Hello', 'Title');
const ok = Application.confirm('Continue?', 'Confirm');
if (ok) { /* ... */ }

const name = Application.prompt('Your name?', 'Name', 'Default');
console.log('User entered: ' + name);

const picked = Application.chooseFile(); // native file picker, returns path
Application.chooseFileAsync((path) => { console.log('Picked: ' + path); });

User paths​

// Snippet — assumes Application is available
const { Application } = require('/application.js');

console.log('Desktop: ' + Application.userDesktopPath);
console.log('Resources: ' + Application.resourcesPath);

Settings​

app.settings exposes application-level preferences that scripts can read or write:

'use strict';
const { Application } = require('/application.js');

// Read-only
console.log('Undo limit: ' + Application.settings.undoLimit);

// Read/write
Application.settings.loadPSDWithEditableText = true;
Application.settings.allowCodeGenerationFromStrings = false;

Key gotchas​

No npm, no node_modules. You cannot install external libraries. Only the built-in SDK modules are available.

console.log() is the only output. Scripts don't return values to the UI. If nothing appears in the console, the script either errored silently or has no log statements.

Script storage. Library scripts are stored in a single binary file (scripts.propcol), not as individual .js files. You cannot read them back with fs at runtime. There is no Save to Library button in the Scripts panel — library saving is available via the MCP server.


Exercises​

Exercise 1.1 — Hello Affinity​

Write a script that logs the application name, version, and platform.

Expected output:

Product: Affinity Designer
Version: x.x
Platform: macOS

Hint: Look at app.productShortName, app.shortVersion, app.platformName.

Exercise 1.2 — Desktop path​

Write a script that logs the Desktop path and confirms it is a non-empty string.

Exercise 1.3 — All open documents​

Write a script that lists every open document's title and whether it has unsaved changes. Use Application.documents.all.

Exercise 1.4 — Module explorer​

require several different modules and log what each exports (use console.log(Object.keys(...))). Get familiar with what's available before you need it.


SDK modules used in this lesson​

  • /application — app singleton

See also​


Example scripts​

01a-app-info.js​

Download 01a-app-info.js

01a-app-info.js
'use strict';

// Example 01a — Application info
// Lesson 01: Environment Setup
//
// Run this first. If it logs cleanly, your environment is working.

const { app } = require('/application.js');

console.log('=== Affinity Application Info ===');
console.log('Product: ', app.productShortName);
console.log('Full name: ', app.productFullName);
console.log('Version: ', app.shortVersion);
console.log('Platform: ', app.platformName);
console.log('Desktop: ', app.userDesktopPath);
console.log('Build kind: ', app.buildKind);
console.log('Suite: ', app.suiteFullName);

01b-module-explorer.js​

Download 01b-module-explorer.js

01b-module-explorer.js
'use strict';

// Example 01b — Module explorer
// Lesson 01: Environment Setup
//
// Inspect what each core SDK module exports.
// A useful reference when you can't remember where something lives.

const modules = [
'/application',
'/document',
'/commands',
'/colours',
'/fills',
'/linestyle',
'/geometry',
'/shapes',
'/dialog',
'/units',
];

for (const m of modules) {
try {
const exports = require(m);
const keys = Object.keys(exports);
console.log(`\n${m} (${keys.length} exports):`);
console.log(' ', keys.join(', '));
} catch (e) {
console.log(`\n${m} — failed to load:`, e.message);
}
}