Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit61a33237e0

README.md

text_observe

What the text system is holding, and which face a label actually shaped with.

The engine lays every text object out against its font database and keeps the result. This module publishes that: how many text objects are live and what they are, the entity each one belongs to, the runtime texture its raster landed in with the bytes it costs, and — the part that exists nowhere else — the font face the shaper reached for, which is a different question from the family the style asked for.

Backed by the __textObserve readings the engine alone can take, joined here with the entity, renderer and font surfaces already in Luau. The public entries are text.observe, text.count, text.alive, text.face, text.faceReasons, text.orphans, text.rasterMemory, font.observe and font.reconcile.

/zero/runtime/text serves the engine's reading before those joins — one serialisation, so a column present in both carries the same value in each. owner.alive, raster.bytes, face.reason and orphans are the joins this module adds to it.

Nothing here runs per frame — the reading is built when a caller asks, which is also what makes it as current in edit mode as in play.

Readings

CallAnswers
observe()every live text object, each with its face, its owner entity and that entity's liveness, and the raster texture its bytes are in; plus orphans, fonts and the glyph-raster total
face(handle)one label: requested, resolved, matched, and a reason from faceReasons()
orphans()the text objects whose owning entity is gone
rasterMemory()glyph-raster bytes, taken out of the one texture map renderer.gpuMemory() totals its textures figure from
reconcile()every registered family held against what the shaper does with it

Why a label is not in the face it named

faceReasons() enumerates the whole set, nearest cause first:

ReasonMeaning
resolvedthe face the shaper used IS the family requested
noFamilyRequestedthe style named no family, so the shaper took the default
notShapedthe object produced no glyphs, so there is no face either way
familyUnknownthe requested family is in no registry entry, so there was nothing to match
familyNotSelectablethe family IS registered, and the shaper still answered with a different face
familyCoveredNoGlyphthe family is one the shaper's font database holds, and its faces cover none of the glyphs asked for — reconcile() reports it, having laid the family out under its own weights and over several scripts

Example

-- Why is this label in the wrong font?
local h = text.create({ content = "Title", fontFamily = "Inter" })
local face = text.face(h)
if face.reason == "familyUnknown" or face.reason == "familyNotSelectable" then
    print(face.requested .. " asked for, " .. face.resolved .. " used — " .. face.reason)
end

-- What is the engine still holding for entities that are gone?
for _, row in ipairs(text.orphans()) do
    print(row.content .. " belongs to " .. row.owner.entityId .. ", which no longer exists")
end

-- What do glyph rasters cost, out of the pool they live in?
local mem = text.rasterMemory()
print(mem.bytes .. " of " .. mem.poolBytes .. " bytes of " .. mem.pool)