# `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.
```nupp
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.
## Constructors
### `newText` _constructor_
```nupp
function newText(value: string?, font: fonts.Font?, size: number?, align: Align?, wrapWidth: number?): Text
```
Builds 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 `"left"` |
| `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
### `Align` _type_
```nupp
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.
### `Text` _record_
```nupp
record Text
text: string
font: fonts.Font?
size: number
align: Align
wrapWidth: number
width: number
height: number
end
```
Lays 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`
```nupp
text: string
```
Caller-writable. Sets the laid-out string. A newline starts a line and
`wrapWidth` may introduce further breaks.
##### `font`
```nupp
font: fonts.Font?
```
Caller-writable. Selects the font that supplies the glyphs. Without one,
the text draws nothing.
##### `size`
```nupp
size: number
```
Caller-writable. Sets the em size in world units.
##### `align`
```nupp
align: Align
```
Caller-writable. Selects the alignment within the block's widest line.
##### `wrapWidth`
```nupp
wrapWidth: number
```
Caller-writable. Sets the maximum line width in world units. Zero
disables wrapping.
##### `width`
```nupp
width: number
```
Engine-owned. Reports the width of the last layout in world units,
before the `Transform2D` scale. Assigning it has no effect.
##### `height`
```nupp
height: number
```
Engine-owned. Reports the height of the last layout in world units, on
the same terms. Assigning it has no effect.
## Functions
### `glyphAt` _function_
```nupp
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 `Text` |
| `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 |
### `glyphsOf` _function_
```nupp
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 `Text` |
#### Returns
| Type | Description |
| --- | --- |
| `{integer}` | a fresh array the caller owns, empty for a text with no glyphs |
### `install` _function_
```nupp
function install(exclusive world: ecs.World): nil
```
Installs 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` | |
### `isReady` _function_
```nupp
function isReady(item: Text): boolean
```
Reports 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 |
### `layouts` _function_
```nupp
function layouts(borrows world: ecs.World): integer
```
Returns 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 |
### `measureIntrinsic` _function_
```nupp
function measureIntrinsic(item: Text): number, number, number
```
Returns 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 |
### `measureText` _function_
```nupp
function measureText(item: Text, wrapWidth: number?): number, number
```
Returns 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 `item.wrapWidth` for this measurement alone, without changing the authored value |
#### Returns
| Type | Description |
| --- | --- |
| `number` | the width at `item.size`, before the `Transform2D` scale, which is zero without a font |
| `number` | the height on the same terms, counting complete line boxes |
### `refresh` _function_
```nupp
function refresh(exclusive world: ecs.World): nil
```
Refreshes 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` | |
### `snap` _function_
```nupp
function snap(value: number): number
```
Rounds 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
### `TextComponent` _variable_
```nupp
const TextComponent: ecs.ComponentDefinition
```
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.
### `TextGlyph` _variable_
```nupp
const TextGlyph: components.Component
```
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.