Skip to main content

Programmatic API

The module exposes an API on window.Tokenizer2 and game.modules.get("tokenizer-2").api once the tokenizer-2.ready hook fires.

Functions

MethodPurpose
openEditor(actor, token?)Open the editor for an existing actor (the same entry the portrait click uses)
openEditorStandalone(opts)Open the editor with no actor - for flows that compose art before an actor exists
tokenize(actor, opts?)Headless single-actor tokenize (no UI)
tokenizeBatch(actors, opts?)Headless batch tokenize
exportLayers(layers, opts?)Render a layer stack to a blob/dataURL
promptConfig(opts?)Show a config dialog; resolves to a config object suitable for tokenize() (or null if cancelled)

openEditorStandalone(options)

Opens the full editor without an Actor document. Saves still render and upload the image(s) to disk, but nothing is written to a document - instead the generated paths and the prototype-token patch are returned so the caller can apply them to an actor it creates afterward. Designed for character-creation wizards (e.g. Hero Mancer) that let the user pick portrait/token art before the actor is created.

const result = await game.modules.get("tokenizer-2").api.openEditorStandalone({
name: "Aria the Wizard", // drives the save filename
type: "character", // "character"/"pc" route to the PC save folder
sourceImage: "path/to/portrait.png",
// optional:
disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY, // default-ring selection
hasPlayerOwner: true, // overrides PC detection (defaults true for character/pc)
targetFolder: "[data] my/folder",// overrides the configured pc/npc save location
userId: game.user.id, // advisory - used only for a FILES_UPLOAD permission check
onComplete: (res) => console.log(res),
});

Returns a Promise that resolves when the editor closes (the onComplete callback fires with the same value):

  • On save, an object: { tokenPath?, avatarPath?, prototypeToken?, avatarUpdate?, layerStack }
    • tokenPath / avatarPath - server paths of the uploaded image(s)
    • prototypeToken - a dotted patch (prototypeToken.texture.src, .texture.scaleX/Y, and in dynamic-ring mode prototypeToken.ring.*) to apply to the new actor
    • avatarUpdate - { [avatarKey]: path } patch for the actor's portrait field
    • layerStack - the serialised layer stack, to store as a flag for future non-destructive re-edits
  • On close without saving, null.

Recipe for applying the result to a freshly-created actor:

if (result) {
await actor.update({ ...result.prototypeToken, ...result.avatarUpdate });
await actor.setFlag("tokenizer-2", "layerStack", result.layerStack);
// Opening Tokenizer 2 on this actor later rehydrates the saved composition.
}

Notes

  • Only one editor can be open at a time; calling this closes any open editor first.
  • Files are written to the configured PC/NPC save locations (by type) unless targetFolder is supplied; the in-editor Save dialog still lets the user tweak folder/filename.
  • The default ring is applied only if the Apply Default Ring setting is enabled; a standalone actor has no real disposition, so it defaults to friendly (or the supplied disposition).

promptConfig(options)

Shows the same options form as the compendium auto-tokenizer (frame, mask, portrait fit, image source, wildcard handling, save folder) but returns the chosen settings instead of running a batch. Designed for external modules (e.g. DDB Importer) that prompt the user once and apply the same config to many imported actors.

const api = game.modules.get("tokenizer-2").api;
const config = await api.promptConfig({
defaults: { saveFolder: "[data] tokenizer/imports" }, // optional
// title: "...", description: "...", previewActor: someActor,
});
if (!config) return; // user cancelled
for (const actor of importedActors) {
await api.tokenize(actor, { ...config, filename: actor.name });
}

Returns Promise<object|null> - the object has the same shape as tokenize() options (forceDynamicRing, forceBakedRing, frameSrc, maskSrc, portraitFit, useActorImg, wildcardMode, saveFolder) and can be spread directly into tokenize(). The preview uses a synthetic standalone actor when no previewActor is supplied.

Pre-creation use: tokenize(actorData, { updateActor: false })

tokenize() can also be used before an actor document exists - for example, when DDB Importer assembles a monster's actor-data and wants to embed the rendered token into that data before calling Actor.create(). Pass updateActor: false to skip every actor mutation while still uploading the file:

const api = game.modules.get("tokenizer-2").api;
const cfg = await api.promptConfig({ defaults: { saveFolder: "[data] imports/tokens" } });

const { path, prototypeToken, layers } = await api.tokenize(actorData, {
...cfg,
filename: actorData.name,
updateActor: false,
});

// Merge the patch into the actor-data being assembled. The keys are dotted, so
// expand before merging.
foundry.utils.mergeObject(actorData, foundry.utils.expandObject(prototypeToken));
actorData.flags ??= {};
actorData.flags["tokenizer-2"] = { layerStack: layers };

await Actor.create(actorData);

With updateActor: false:

  • The blob is still uploaded to the configured (or supplied) save folder.
  • actor.update, actor.setFlag, and the placed-token patch are all skipped.
  • result.prototypeToken carries the exact dotted-key patch that the writes would have used, including the cache-busted prototypeToken.texture.src.
  • result.layers is the serialised layer stack, ready for setFlag or merging into flags["tokenizer-2"].layerStack.