Advanced / Composition · guide
Templates (createTemplate)
Current Apexify.js 6.0.0 documentation for Templates (createTemplate).
ApexPainter#createTemplate(definition, options?) captures an immutable copy of a scene-shaped definition and returns a TemplateHandle.
| Method | Returns | Purpose |
|---|---|---|
toRenderInput(data, opts?) | Promise<SceneRenderInput> | Resolve the template without rasterizing; useful for tests and scene→GIF/video workflows. |
render(data, opts?) | Promise<Buffer> | Resolve, validate, then render one PNG. |
TemplateHandle snapshots both the definition and each render's data before asynchronous layout work. Mutating caller-owned objects after createTemplate() or after starting a render does not change that render.
Resolution order
The supported pipeline is deterministic:
- Apply render-time insertions.
- Validate unique literal layer
idvalues. - Apply overrides by id.
- Evaluate
visibleand remove hidden subtrees. - Resolve
{{placeholders}}. - Resolve
$assets. - Normalize numeric layout fields and shorthand layers.
- Expand flex/grid layouts.
- Validate the resulting
SceneRenderInputwith the normal scene limits.
Hidden layers are removed before their other placeholders/assets are resolved, so a missing value inside an intentionally hidden layer does not fail the render.
Placeholders
{{key}}— required. Missing ornull/undefinedvalues throwTemplateResolveError.{{key | default}}— the explicit default is used only for missing/nullish values.- Dotted own-property paths such as
{{user.name}}are supported. - A placeholder that occupies the entire string field preserves the native value.
0,false, and""are not treated as missing. - An embedded placeholder inside a longer string is stringified.
Preserving an explicit empty string does not bypass the final scene contract. If "" resolves into a field that requires a non-empty string, such as a text layer's text, toRenderInput() / render() rejects the final scene during validation. Apexify.js does not silently substitute the placeholder default or drop the layer; use visible when an empty value should intentionally suppress content.
Unsafe prototype-path segments are not traversed.
Shorthand layers
Template definitions may use document-style shorthand:
{ type: "text", text: "…", … }→ scenetextsform.{ type: "image", source: "…", … }→ sceneimagesform.
The final SceneRenderInput contains normal scene layers.
Minimal example
Visibility
visible accepts booleans, numbers, literal strings, or placeholder strings. Common string values are interpreted explicitly: true, 1, yes are true; false, 0, no, and the empty string are false.
For a whole placeholder such as visible: "{{feature.enabled}}", the native boolean/number/string value drives visibility.
Overrides and insertions
Every targetable layer id must be a unique, non-empty literal string. Placeholder ids are rejected.
Deep overrides
Overrides use the authored template-layer shape and deep-merge plain nested objects. Unknown ids are rejected instead of being silently ignored.
Deterministic insertions
Each insertion target must exist exactly once, and insertions may not introduce duplicate ids.
Flex layout
A type: "layout" node with layout.type: "flex" expands to absolutely positioned children.
| Field | Meaning |
|---|---|
direction | row (default) or column |
gap, padding | Non-negative pixels |
align | Cross axis: start, center, end |
justify | Main axis: start, center, end, space-between |
Text children are measured with measureText; image children require positive explicit width/height. Layout containers also require positive width/height.
Grid layout
layout.type: "grid" supports positive integer columns, non-negative gap / padding, and start / center / end alignment and justification. Cell width is derived from the container; row height is the tallest child in that row. Invalid geometry that leaves no positive cell area throws TemplateResolveError.
Asset resolution
After placeholders, the shared asset-reference engine resolves $name, dotted paths, $$ escaping, whole-field structured/Buffer references, and scalar embedded references. Unknown assets become TemplateResolveError with the asset token and original cause.
Pass createTemplate(definition, { resolveAssetRef }) when a template needs a custom resolver instead of painter.assets.
render() deliberately calls the final scene render with resolveAssetRefs: false because the template stage already resolved its assets.
toRenderInput
The returned object is an isolated, validated SceneRenderInput snapshot. Mutating it does not mutate the template definition or later renders.