tecs.gfx.text
Shaped text as entities in the rendered world.
A Text names a font and a string. Transform2D places its top-left corner and Tint colors every glyph. The layout system turns one text into one glyph entity per drawn character, each an ordinary textured quad sampling the font's atlas, so text moves, layers, and draws through exactly the path a sprite does.
const font = assert(tecs.gfx.fonts.newTTF({source = "assets/fonts/JetBrainsMono-ExtraBold.ttf"}))
tecs.gfx.text.install(world)
world:spawn(
tecs.ecs.Transform2D(24, 24),
tecs.gfx.Tint(0.92, 0.96, 1.0, 1.0),
tecs.gfx.Text("tecs\n1200 entities", font, 28, "center")
)Write text fields through world:getMut. A write through world:get leaves the column clean and the drawn glyphs stale.
Layout#
Text supports explicit newlines, left, center, and right alignment, and wrapping to a width. It does not anchor outside the top-left corner or style individual glyphs. Alignment moves each line within the widest line of the block, and wrapping breaks between words, letting a single word wider than the wrap width overflow rather than splitting it.
Transform2D on a text entity scales the whole block: the glyph quads take their size from Text.size, and scaleX and scaleY multiply what comes out. That is the one place a Transform2D means a factor rather than a size in world units.
Glyph entities#
Every drawn character is an entity carrying Transform2D, Tint, Sprite, Renderable2D, and the TextGlyph tag. They belong to the layout system: spawning, despawning, or writing one by hand is undone the next time its text changes. A snapshot stores them like any other entity, and the layout system despawns the restored ones on its next run because no live text owns them, so a loaded world rebuilds its text rather than doubling it.
A layout reserves missing glyphs in one batch and initializes their native component columns at the following barrier. Existing glyphs retain their IDs shortening a label releases only its surplus, and unchanged labels do no layout or glyph-creation work.
Module contents
Constructors
| Constructor | Description |
|---|---|
newText | Builds a text value that belongs to no entity. |
Types
| Type | Kind | Description |
|---|---|---|
Align | type | Selects where a line sits within the widest line of its block. |
Text | record | Lays a string out into glyph entities. |
Functions
| Function | Kind | Description |
|---|---|---|
glyphAt | function | Returns one drawn glyph's world centre and size. |
glyphsOf | function | Returns the glyph entities one text owns, in drawn order. |
install | function | Installs text layout into a world. |
isReady | function | Reports whether a text's atlas has reached the backend. |
layouts | function | Returns how many texts a world has laid out. |
measureIntrinsic | function | Returns the preferred and minimum-content metrics for a text item. |
measureText | function | Returns a text item's width and height in world units. |
refresh | function | Refreshes changed text immediately after retained layout changes its boxes. |
snap | function | Rounds a world coordinate to the nearest whole unit. |
Values
| Value | Kind | Description |
|---|---|---|
TextComponent | variable | The process-wide Text component definition. |
TextGlyph | variable | Marks an entity as one glyph the layout system owns. |
Constructors#
newTextconstructor#
function newText(value: string?, font: fonts.Font?, size: number?, align: Align?, wrapWidth: number?): TextBuilds a text value that belongs to no entity.
measureText and measureIntrinsic take one of these, so a caller sizes a layout before spawning anything. Spawning goes through Text itself, which is the component and builds the same value.
Arguments
| Name | Type | Description |
|---|---|---|
value | string? | the string to lay out, defaulting to empty |
font | fonts.Font? | the font supplying the glyphs, or nil to draw nothing |
size | number? | the em size in world units, defaulting to sixteen |
align | Align? | the alignment, defaulting to |
wrapWidth | number? | the maximum line width in world units, defaulting to zero, which disables wrapping |
Returns
| Type | Description |
|---|---|
Text | the text value, which the caller owns |
Raises
when the alignment is not one of its declared values, or when the wrap width is negative
Types#
Aligntype#
type Align = "left" | "center" | "right"Selects where a line sits within the widest line of its block.
These identifiers are stored in a snapshot and are a compatibility surface.
Textrecord#
record Text
text: string
font: fonts.Font?
size: number
align: Align
wrapWidth: number
width: number
height: number
endLays a string out into glyph entities.
The entity's Transform2D places the top-left corner of the text block and orients and scales the whole of it, and its Tint colors every glyph. Both are ordinary components on an ordinary entity, so a text moves, tweens, and layers like anything else.
Fields
text#
text: stringCaller-writable. Sets the laid-out string. A newline starts a line and wrapWidth may introduce further breaks.
font#
font: fonts.Font?Caller-writable. Selects the font that supplies the glyphs. Without one, the text draws nothing.
wrapWidth#
wrapWidth: numberCaller-writable. Sets the maximum line width in world units. Zero disables wrapping.
width#
width: numberEngine-owned. Reports the width of the last layout in world units, before the Transform2D scale. Assigning it has no effect.
height#
height: numberEngine-owned. Reports the height of the last layout in world units, on the same terms. Assigning it has no effect.
Functions#
glyphAtfunction#
function glyphAt(borrows world: ecs.World, entity: integer, index: integer): number?, number?, number?, number?Returns one drawn glyph's world centre and size.
Reads the glyph entity rather than laying the text out again, so it reports the placement that is being drawn.
Arguments
| Name | Type | Description |
|---|---|---|
borrows world | ecs.World | the world that contains the text entity |
entity | integer | an entity carrying |
index | integer | a one-based drawn-glyph index; whitespace takes no index |
Returns
| Type | Description |
|---|---|
number? | the world x of the glyph centre, or nil when no such glyph exists |
number? | the world y of the glyph centre, or nil with the first return |
number? | the glyph width in world units, or nil with the first return |
number? | the glyph height in world units, or nil with the first return |
glyphsOffunction#
function glyphsOf(borrows world: ecs.World, entity: integer): {integer}Returns the glyph entities one text owns, in drawn order.
Arguments
| Name | Type | Description |
|---|---|---|
borrows world | ecs.World | the world that contains the text entity |
entity | integer | an entity carrying |
Returns
| Type | Description |
|---|---|
{integer} | a fresh array the caller owns, empty for a text with no glyphs |
installfunction#
function install(exclusive world: ecs.World): nilInstalls text layout into a world.
Installing twice does nothing, so a world may install it directly rather than relying on the application having done so.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive world | ecs.World | the world receiving the layout system and its ownership tables |
Returns
| Type | Description |
|---|---|
nil |
isReadyfunction#
function isReady(item: Text): booleanReports whether a text's atlas has reached the backend.
Extraction draws a glyph whose atlas is not resident against the backend's white fallback, which is a solid block rather than a letter, so a caller that must not show that waits on this. Asking queues whatever the atlas gained, exactly as tecs.gfx.fonts.imageOf does.
Arguments
| Name | Type | Description |
|---|---|---|
item | Text | the text to inspect |
Returns
| Type | Description |
|---|---|
boolean | whether the font's atlas is resident, which is false without a font |
layoutsfunction#
function layouts(borrows world: ecs.World): integerReturns how many texts a world has laid out.
Counts rows laid out rather than frames, so a scene whose text is settled leaves it still. A test asserts on that to prove the dirty gate holds.
Arguments
| Name | Type | Description |
|---|---|---|
borrows world | ecs.World | the world to inspect |
Returns
| Type | Description |
|---|---|
integer | a count that only increases, or zero before installation |
measureIntrinsicfunction#
function measureIntrinsic(item: Text): number, number, numberReturns the preferred and minimum-content metrics for a text item.
The minimum-content width is the widest single word, which is the narrowest a wrapping layout can be made without splitting one.
Arguments
| Name | Type | Description |
|---|---|---|
item | Text | a text value with a font |
Returns
| Type | Description |
|---|---|
number | the preferred width, with wrapping disabled |
number | the preferred height, with wrapping disabled |
number | the minimum-content width |
measureTextfunction#
function measureText(item: Text, wrapWidth: number?): number, numberReturns a text item's width and height in world units.
Runs the same shaping the layout system runs, without touching an entity or making a glyph resident.
Arguments
| Name | Type | Description |
|---|---|---|
item | Text | a text value to read, which need not belong to an entity |
wrapWidth | number? | overrides |
Returns
| Type | Description |
|---|---|
number | the width at |
number | the height on the same terms, counting complete line boxes |
refreshfunction#
function refresh(exclusive world: ecs.World): nilRefreshes changed text immediately after retained layout changes its boxes.
Arguments
| Name | Type | Description |
|---|---|---|
exclusive world | ecs.World | the world whose text and glyph entities are synchronized |
Returns
| Type | Description |
|---|---|
nil |
snapfunction#
function snap(value: number): numberRounds a world coordinate to the nearest whole unit.
An alpha-raster font drawn at its loaded size lines its texels up with the target's only when the block's origin is whole, so a screen-space label snaps its position through this before writing it.
Arguments
| Name | Type | Description |
|---|---|---|
value | number | the coordinate to snap |
Returns
| Type | Description |
|---|---|
number | the nearest whole value, with a half rounding away from zero |
Values#
TextComponentvariable#
const TextComponent: ecs.ComponentDefinition<Text>The process-wide Text component definition.
The component name and the text, font, size, align, and wrapWidth snapshot keys are a compatibility surface. A snapshot stores the font by name, because a font is a shared table rather than a value.
TextGlyphvariable#
Marks an entity as one glyph the layout system owns.
Game code neither adds nor removes it. It is public so a query can exclude the glyphs a text produced, and its name is a compatibility surface.