Inline token substitution — the templating model shared with
phoenix_kit_og, ported for byte-compatibility so stored templates
migrate without rewriting bindings.
Two bracket styles, both \w+ names, both resolved from a single values
map:
{{slot}}— a template-local slot, wired to a concrete value per render (the post title, hero src, …). Listed byslots/1for a wiring UI, with a:text/:imagetype inferred from where it appears.[[global]]— a global that resolves from ambient context (site host, page URL, locale). Same substitution pass, different bracket; not listed as a slot.
Callers merge globals + wired slot values into one map (see
OpenFresco.render_svg/3's :globals option).
The substitution contract (one path, both surfaces)
The editor stage and the PNG rasterizer resolve values through this exact module — there is no second substitution path — so what the author sees on the stage is what renders. The contract is:
- Bracket styles —
{{slot}}(per-render wiring) and[[global]](ambient context). Both name-match\w+. - Undefined tokens pass through literally. An unwired
{{Title}}renders as the visible text{{Title}}— og's "needs wiring" signal — never as an error or empty string. This is deliberate: a missing wiring should be obvious in the card, not silent. - Escaping is the renderer's job, applied by default. Substitution
returns plain text;
OpenFresco.SvgXML-escapes every substituted value at the emission site. There is no "raw" opt-out — a template cannot inject markup through a slot value (seeOpenFresco.Conformance). Hosts that need markup compose it into the scene as elements, not as substituted strings. - Types — non-binary values (
nil, numbers, a whole-value%{placeholder: k}) are coerced (nil→"", others viato_string/1); the placeholder form scans as its{{k}}token.
Deterministic: apply/2 is a pure function of (text, values).
Summary
Functions
Substitute {{slot}} and [[global]] tokens in text from values
(string keys). Unknown names pass through unchanged. A nil text is "".
The {{slot}} names used across a scene, in first-appearance order, each
tagged with the :text / :image type inferred from the field it appears
in. Feeds a wiring UI (the phoenix_kit_og Assignments equivalent).
Whether a substituted string still carries an unresolved {{slot}} token
(used by the image path to decide between drawing the resolved src and the
neutral stand-in).
Functions
Substitute {{slot}} and [[global]] tokens in text from values
(string keys). Unknown names pass through unchanged. A nil text is "".
A whole-value placeholder (%{placeholder: "k"}) is accepted as a
degenerate case — treated as the string "{{k}}".
@spec slots(OpenFresco.Scene.t()) :: [%{name: String.t(), type: :text | :image}]
The {{slot}} names used across a scene, in first-appearance order, each
tagged with the :text / :image type inferred from the field it appears
in. Feeds a wiring UI (the phoenix_kit_og Assignments equivalent).
Whether a substituted string still carries an unresolved {{slot}} token
(used by the image path to decide between drawing the resolved src and the
neutral stand-in).