Typography specs — Engine.useFont, multi-line, word-wrap, textAlign
Hero composition over any photo: title + subtitle + body paragraph + code snippet, all driven by reusable `Engine.useFont()` specs. Stage 2 of the font-engine work — declare a style once, apply it many times, derive variants with `.with()` without restating every field. `\n` introduces explicit line breaks; `maxWidth` triggers heuristic word-wrap so paragraphs fit a column. `textAlign` (`"left"` / `"center"` / `"right"`) drives anchor placement per line. Great as a starting point for cover-image generators, social-media hero cards, photo-with-overlay tooling, or any "title + tagline + body" presentation that would otherwise need a layout library.
INPUT
Photo + typographic overlay
JavaScript
// Reusable typography specs + multi-line text + word-wrap on top of a
// photo background. Demonstrates Engine.useFont() (Stage 2 of the
// font-engine work) — declare a style once, apply it many times,
// optionally derive variants with .with().
// demo_font_layout.js
//!INPUT: INPUT
//!OUTPUT: OUTPUT
//!PARAM: TITLE:string=OpticScript
//!PARAM: SUBTITLE:string=Native-speed image processing for everyone
const img = Engine.loadImage(INPUT);
const W = img.width, H = img.height;
// Darken the photo slightly so the white text reads cleanly.
img.brightness(0.55).vignette(0.4);
// ── Reusable specs ─────────────────────────────────────────────────
// One declaration, many applications. .with() spawns a variant with
// one or two fields overridden — keeps related styles visually linked.
const titleStyle = Engine.useFont("Inter", Math.round(W / 12), {
color: "#ffffff",
textAlign: "center",
lineHeight: 1.05,
});
const subtitle = titleStyle.with({
size: Math.round(W / 30),
color: "#ffe080",
});
const body = Engine.useFont("Inter", Math.round(W / 50), {
color: "#e8e8f0",
textAlign: "left",
lineHeight: 1.5,
maxWidth: Math.round(W * 0.55),
});
const monoCaption = Engine.useFont("JetBrains Mono", Math.round(W / 70), {
color: "#888",
textAlign: "right",
});
// ── Title block (centered) ─────────────────────────────────────────
img.drawText(TITLE, W / 2, H * 0.30, titleStyle);
img.drawText(SUBTITLE, W / 2, H * 0.40, subtitle);
// ── Body paragraph (auto-wrapped at maxWidth) ──────────────────────
// Heuristic word-wrap — the engine splits the sentence into greedy
// lines so each one fits inside maxWidth. Precise per-string
// measurement arrives in Stage 3 (Engine.measureText).
img.drawText(
"Engine.useFont() produces a reusable spec — declare a style " +
"once, apply it many times. Multi-line and word-wrap come for " +
"free; .with() derives related variants without restating every " +
"field.",
W * 0.06, H * 0.55, body,
);
// ── Code overlay (mono, multi-line via \n) ────────────────────────
// Pre-shrunk font size + manual line breaks. Notice both the mono
// font and the right-aligned monoCaption use the same drawText call —
// it's just a string that happens to have \n inside.
img.drawText(
"const h1 = Engine.useFont('Inter', 48, {\n" +
" color: '#fff', textAlign: 'center'\n" +
"});\n" +
"img.drawText('Hello', W/2, 60, h1);",
W * 0.06, H * 0.78,
Engine.useFont("JetBrains Mono", Math.round(W / 55), {
color: "#5fb3e9",
textAlign: "left",
lineHeight: 1.35,
}),
);
// Bottom-right caption — right-aligned text needs no manual width math.
img.drawText("MLC OpticScript · Engine.useFont()", W - W * 0.04, H - H * 0.04, monoCaption);
img.save(OUTPUT);
img.free();
// © 2026 Michael Lechner · mlc OpticScript · https://mlcgo.eu · Elastic License 2.0