Text and fonts
A Text node draws a string. A Font is the typeface it uses. willow draws most fonts as signed distance fields (SDF), so text stays sharp at any size and scale.
A label
ts
import { Text, Font } from "willow";
class Title {
static main(): void {
const title: Text = new Text("Welcome", Font.system());
title.fontSize = 48;
title.color = Color.hex("#FFE9A8");
title.align = "center";
title.alignPivot();
title.x = 400;
title.y = 120;
engine.root2d.add(title);
}
}new Text(string) without a font uses the default font. Assigning text, font, fontSize or style lays the text out again on the next frame.
Text properties
| Property | Meaning | Default |
|---|---|---|
text | The string. | |
font | The Font. | willow's bundled font |
fontSize | Size in pixels. | 16 |
color | Fill colour, a Color. | white |
align | "left", "center" or "right". | "left" |
wrapWidth | Wrap lines to this width in pixels. 0 means no wrapping. | 0 |
lineHeight | Line spacing multiplier. | 1 |
style | "regular", "bold", "italic" or "boldItalic". | "regular" |
sharpness | SDF edge sharpness, 0 to 1. Higher narrows the soft edge. | 0 |
pixelSnap | Puts the text on whole pixels when not rotated, which keeps small text crisp. Turn it off for slowly moving text so it glides. | true |
width, height | Measured size, after the first layout. |
measure() lays the text out right away and returns its { width, height }, so you can size a panel before the first frame.
Outline, glow and shadow
Each Text has an effects object. A width of 0 turns an effect off.
ts
import { Text } from "willow";
class Damage {
static main(): void {
const hit: Text = new Text("-25");
hit.fontSize = 36;
hit.color = Color.hex("#FF5A4F");
hit.effects.outlineWidth = 3;
hit.effects.outlineColor = Color.BLACK;
hit.effects.shadowOffsetX = 2;
hit.effects.shadowOffsetY = 3;
hit.effects.shadowColor = Color.hex("#00000099");
hit.x = 300;
hit.y = 200;
engine.root2d.add(hit);
}
}glowWidth and glowColor add a soft glow.
Fonts
| Factory | Loads |
|---|---|
Font.system() | willow's bundled default font. |
Font.load(path) | A .fontbundle file (baked ahead of time with thicket tool fontgen). |
Font.fromBuffer(buffer) | A font bundle already in memory. |
Font.loadTTF(path, config?) | A TTF or OTF file, baked once while it loads. |
Font.fromTTF(buffer, config?) | TTF or OTF bytes in memory, baked once. |
Font.loadTTFCached(ttf, cacheDir, options?) | A TTF or OTF, baked the first time and saved as a bundle in cacheDir; later runs load the saved bundle. |
Font.fromPixelFont(texture, cellW, cellH, chars) | A bitmap font sheet of fixed-size cells, in row order. |
Baking never happens per frame. For a shipped game, bake fonts ahead of time with fontgen or let loadTTFCached keep the result.
ts
import { Text, Font } from "willow";
class Fonts {
static main(): void {
const body: Font = Font.loadTTFCached("assets/fonts/Inter.ttf", ".cache/fonts", { sizes: [32], charset: "latin" });
const pixel: Font = Font.fromPixelFont("assets/fonts/pixel.png", 8, 8, " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ");
const a: Text = new Text("Smooth at any size", body);
a.fontSize = 28;
a.y = 40;
engine.root2d.add(a);
const b: Text = new Text("PIXEL FONT", pixel);
b.fontSize = 16;
b.y = 100;
engine.root2d.add(b);
}
}font.measure(text, size) measures a string without making a node.
Text input
A Text with type = TextFieldType.INPUT takes typing while it has focus. Give it focus with engine.scene.focus = field.
ts
import { Text, TextFieldType, TextInputEvent } from "willow";
class NameEntry {
static main(): void {
const field: Text = new Text("");
field.type = TextFieldType.INPUT;
field.maxChars = 12;
field.restrict = /[A-Za-z0-9 ]/;
field.x = 100;
field.y = 100;
engine.root2d.add(field);
engine.scene.focus = field;
field.onTextInput((e: TextInputEvent): void => {
if (e.text === "#") {
e.preventDefault();
}
});
field.onChange((): void => {
console.log("name is now " + field.text);
});
}
}maxCharslimits the length;restrictis a pattern each typed character must match.onTextInputruns before text is added and can cancel it withpreventDefault().onChangeruns after typing or Backspace changestext.onTextCompositionreports IME pre-edit text (for languages typed through an input method). It never changestext.
A plain input Text supports typing and Backspace at the end. For a caret, selection and clipboard, use willowui's TextInput or TextArea.
Next
- Shapes and meshes
- Reference: Text, Font