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

Advanced / Composition · guide

Named assets (painter.assets)

Current Apexify.js 6.0.0 documentation for Named assets (painter.assets).

apexify.jsRuntime: nodeCURRENTSince 6.0.0

AssetManager is the named composition registry on painter.assets. It stores images, font paths, palettes, and arbitrary JSON-like values, then resolves $name / dotted $value.path references for scenes, templates, and opt-in imperative APIs.

  • renderScene, renderSceneToGIF, renderSceneToVideoFrames — asset resolution is on by default; pass resolveAssetRefs: false to skip it.
  • Templates — placeholders resolve first, then asset references resolve during TemplateHandle.render / toRenderInput.
  • SceneBuilder.render — asset resolution is off by default; opt in with { resolveAssetRefs: true }.
  • Imperative create APIs / batch / chain — resolution is opt-in; see Imperative & batch resolution.

Registering assets

SOURCEtypescript
typescript
Studio
import { ApexPainter } from "apexify.js"; const painter = new ApexPainter({ type: "buffer" }); painter.assets.loadImage("logo", "./brand/logo.png");painter.assets.loadFont("heading", "./fonts/Inter-Bold.ttf");painter.assets.loadPalette("theme", {  bg: "#020617",  text: "#f8fafc",  muted: "#64748b",});painter.assets.loadValue("copy", {  hero: { title: "Apexify", enabled: true },  spacing: [8, 16, 24],});

Duplicate and replacement contract

Root names are unique across the whole registry. loadImage, loadFont, loadPalette, and loadValue throw ApexifyAssetError when that name is already registered. Replacement is explicit:

  • replaceImage(name, source)
  • replaceFont(name, path)
  • replacePalette(name, colors)
  • replaceValue(name, value)

A replace call also throws when the target name does not exist. This prevents accidental overwrite during application startup.

Cleanup/introspection:

  • has(name) — root-name existence check.
  • delete(name) — remove any asset kind by root name.
  • unregisterImage, unregisterFont, unregisterPalette — kind-specific removal helpers.
  • list() — returns { name, kind } registrations.
  • clear() — empties the registry.

Registered JSON-like data and Buffers are copied on ingress, and resolve() returns an isolated copy. Mutating the original registration value or a resolved Buffer does not mutate registry storage.


Reference syntax

Call assets.resolve() without the leading dollar sign:

SOURCEtypescript
typescript
Studio
painter.assets.resolve("logo");painter.assets.resolve("theme.text");painter.assets.resolve("copy.hero.title");painter.assets.resolve("copy.spacing.1");

In composition data, use the leading $:

Value in configMeaning
"$logo"Resolve the complete logo asset. A lone reference may return a string, scalar, object/array value, or Buffer.
"$theme.text"Dotted own-property lookup.
"$copy.spacing.1"Array indices are allowed in dotted paths.
"color=$theme.text"Embedded references are allowed only when they resolve to string/number/boolean scalars.
"$$theme.text"Literal $theme.text; $$ escapes a dollar sign.

Unknown roots, missing nested properties, unsafe path segments, and attempts to embed a non-scalar asset inside a longer string throw ApexifyAssetError. Use a non-scalar reference as the entire field value instead.

The deep resolver rejects cyclic arrays/plain objects rather than recursing indefinitely. Opaque runtime objects are preserved; JSON-like arrays/records are traversed.


Example — scene + palette + image

SOURCEtypescript
typescript
Studio
import { ApexPainter } from "apexify.js";import fs from "node:fs"; const painter = new ApexPainter({ type: "buffer" }); painter.assets  .loadImage("avatar", "./fixtures/user.png")  .loadPalette("brand", { panel: "#1e293b", ink: "#e2e8f0" }); const png = await painter.renderScene({  width: 480,  height: 240,  background: { colorBg: "$brand.panel" },  layers: [    {      type: "text",      texts: {        text: "Signed in",        x: 24,        y: 36,        fontSize: 22,        color: "$brand.ink",      },    },    {      type: "image",      images: { source: "$avatar", x: 320, y: 40, width: 112, height: 112 },    },  ],}); fs.writeFileSync("card.png", png);

Use loadFont plus a full-field font path reference when a text API accepts a font path string.


prepareForRender

painter.prepareForRender<T>(value): T deep-resolves asset references in JSON-like arrays/records without rendering anything. It is useful when an imperative API does not expose an asset-resolution option or when you want one resolved snapshot reused across calls.

SOURCEtypescript
typescript
Studio
const base = painter.prepareForRender({  width: 720,  height: 400,  colorBg: "$theme.bg",}); await painter.createCanvas(base);

Because resolution returns a new composition structure, the input object is not mutated.


Relationship to templates

Templates use one deterministic pipeline: visibility filtering → placeholder resolution → asset resolution → numeric/layout normalization → scene validation. A whole placeholder or asset reference can preserve native values such as false, 0, arrays, objects, or Buffers where the target field accepts them.

Use createTemplate(definition, { resolveAssetRef }) when one template needs a custom asset resolver instead of painter.assets.


Next steps