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
appsingleton — 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:
| Feature | Affinity SDK | Node.js |
|---|---|---|
| Module imports | require('/module.js') | require('./module') or ESM |
| Package manager | None — built-in modules only | npm |
| Output | console.log() → Script console | stdout |
| Return values | Scripts return nothing | Functions return values |
| File access | Desktop + granted folders | Any path |
| Network | require('/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.jsfiles. You cannot read them back withfsat 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—appsingleton
See also
- Lesson 02 — App & Document
- examples/ — runnable scripts for this lesson
Example scripts
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
'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);
}
}