# `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.