Skip to content
Apexify.jsDocs
Apexify.js version v5.4.5

Advanced / Composition · guide

Imperative APIs, SceneBuilder.render, batch & chain

Current Apexify.js 6.0.0 documentation for Imperative APIs, SceneBuilder.render, batch & chain.

apexify.jsRuntime: nodeCURRENTSince 6.0.0

Scene entry points resolve $ references by default. Imperative helpers and SceneBuilder.render() default to literal values unless you explicitly opt in.


Resolution matrix

Entry pointDefaultControl
renderScene, scene step of renderSceneToGIF, scene step of renderSceneToVideoFramesResolve $ refs{ resolveAssetRefs: false } to skip
SceneBuilder.render from painter.createScene()No resolution{ resolveAssetRefs: true }
createCanvas, createImage, createText, measureText, chart helpers, createGIF, animate, createVideoNo resolutionSupported trailing PainterAssetRefsOptions with { resolveAssetRefs: true }
batch, chainNo resolution{ resolveAssetRefs?: boolean; resolve?: AssetResolveFn }
TemplatesResolve inside template pipelineCustom resolver may be supplied when creating the template

Templates call the final renderScene with asset resolution disabled because their scene snapshot is already resolved.


Imperative canvas

SOURCEtypescript
typescript
Studio
import { ApexPainter } from "apexify.js"; const painter = new ApexPainter({ type: "buffer" });painter.assets.loadPalette("app", { canvas: "#020617", fg: "#f8fafc" }); await painter.createCanvas(  {    width: 400,    height: 240,    colorBg: "$app.canvas",  },  { resolveAssetRefs: true });

Without the trailing opt-in, $app.canvas remains a literal string.


SceneBuilder

SOURCEtypescript
typescript
Studio
const painter = new ApexPainter({ type: "buffer" });painter.assets.loadImage("badge", "./badge.png"); const scene = painter.createScene({  width: 320,  height: 180,  background: { colorBg: "#0f172a" },  layers: [    {      type: "image",      images: { source: "$badge", x: 24, y: 24, width: 48, height: 48 },    },  ],}); const png = await scene.render({ resolveAssetRefs: true });

Builders created through ApexPainter.createScene() carry the painter's asset resolver. Direct low-level SceneBuilder construction without a resolver cannot resolve $ references.


batch

SOURCEtypescript
typescript
Studio
const painter = new ApexPainter({ type: "buffer" });painter.assets.loadPalette("app", { canvas: "#020617", fg: "#f8fafc" }); await painter.batch(  [    { type: "canvas", config: { width: 200, height: 120, colorBg: "$app.canvas" } },    {      type: "text",      config: {        texts: { text: "Hi", x: 10, y: 24, fontSize: 18, color: "$app.fg" },      },    },  ],  { resolveAssetRefs: true });

chain uses the same BatchChainAssetOpts. When resolution is enabled, Apexify walks batch config objects or non-current chain arguments using the shared asset-reference engine.

A custom resolve function uses the public AssetResolveFn contract and may return supported AssetValue data, including scalars, Buffers, arrays, and plain records. The target field still needs to accept the resolved value; embedded-in-string references remain scalar-only.


prepareForRender

Use prepareForRender() when you want one resolved snapshot reused by several imperative calls.

SOURCEtypescript
typescript
Studio
const cfg = painter.prepareForRender({  width: 600,  height: 400,  colorBg: "$app.canvas",}); await painter.createCanvas(cfg);

The input composition is not mutated. JSON-like records/arrays are copied, Buffers are copied, $$ escapes literal dollar signs, and cyclic composition graphs are rejected rather than recursing indefinitely.


Whole-field vs embedded references

SOURCEtypescript
typescript
Studio
painter.assets.loadValue("flags", { enabled: false, count: 0 }); const prepared = painter.prepareForRender({  enabled: "$flags.enabled",       // boolean false preserved  count: "$flags.count",           // numeric 0 preserved  label: "count=$flags.count",     // embedded scalar -> "count=0"  literal: "$$flags.count",        // literal "$flags.count"});

Whole-field references preserve their native value. Embedded references are converted to text and therefore must resolve to string/number/boolean scalars.

Back to Composition hub.


Next steps