Changelog
All notable changes to UniText.
Versions
to
2.2.5
2026-05-15
- AddedPer-occurrence sprite color:
<sprite=name,i>tints the inline sprite with the host UniText component's color (CSScurrentColorequivalent);<sprite=name,#FF0000>(or any hex / named color) overrides per occurrence. Omitting the second argument keeps the sprite's original colors as before. - AddedSprite color inspector: the
SpriteModifierparameter editor exposes an Original / Inherit / Override dropdown — choosing Override reveals a color picker — that serializes directly into the tag. - Added
InlineMediaModifier.OnExtraTokenshook: custom inline-media modifier subclasses can parse additional comma-separated arguments after the entry name (per-occurrence tag attributes) without touching the base class. - Added
variant:[ParameterField]type: declare an enum of options where each option is either a literal token or a typed sub-field (color,float,int,bool), so a single tag slot shows a dropdown plus a conditional value editor in the parameter inspector.
- Changed
InlineMediaModifier<TEntry, TWrapper>.ConfigureWrappernow takes the cluster index as a third parameter (breaking for custom inline-media modifier subclasses): use it to apply per-occurrence overrides parsed inOnExtraTokens.
- Fixed
ShadowModifier.FixedPixelSizeoffset uneven per glyph: withFixedPixelSizeon, each glyph's shadow shifted by a different distance instead of all glyphs sharing one on-screen offset.
2.2.4
2026-05-13
- AddedAdd Component inherits project default prefab settings: adding
UniTextorUniTextWorldvia Add Component (or Reset in the inspector) now seeds its serialized fields from the prefab assigned in Project Settings → UniText (Text Prefab/World Text Prefab).
2.2.3
2026-05-13
- ChangedCompact font-size inspector row: Font Size and Auto Size now share a single row, and when Auto Size is on, Min, Max, and Current Size share one row instead of three.
- ChangedLayout "Advanced" foldout: Base Direction, Over Edge, Under Edge, and Leading Distribution moved into a collapsible Advanced foldout inside the Layout section, leaving wrap and alignment as the only fields visible by default.
- FixedTooltips missing on colored toggle buttons: the Auto Size, Word Wrap, alignment, preset, and Expand / Highlight / Rendered toggles in the inspector showed no tooltip on hover even when the underlying serialized field declared one.
2.2.2
2026-05-12
- FixedTag attribute values lost
<and>literals: a quoted attribute value containing<or>(e.g. Unity Input System binding paths like<sprite="<Keyboard>/a">) was truncated at the first inner>; values wrapped in"…"or'…'now preserve any<>characters verbatim with no entity escaping.
2.2.1
2026-05-12
- FixedEdits to a
StylePresetskipped components that had it empty at load: when components were initialized with the preset still empty, later additions to the preset (inspector orAddStyle) had no effect on those components until they were disabled and re-enabled.
2.2.0
2026-05-12
- Added
SpriteModifier(default tag namesprite): embedSpriteassets inline with text without authoring a prefab per icon. The catalog of named sprites is supplied by anISpriteProvider— built-in providers areInlineSpriteProvider(default — list edited on the modifier) andAssetSpriteProvider(sharedUniTextSpritesasset). Custom providers (input-prompt icons, localisation, item icons) implementISpriteProviderdirectly and raiseChangedwhen their resolution result changes. - AddedShared inline-object catalog (
UniTextObjectsasset, Assets → Create → UniText → Objects): named inline-prefab catalog for<obj=name>tags shared across components — alternative to editing the inline list per modifier. Mirrors the existingUniTextGradientsand the newUniTextSprites(Assets → Create → UniText → Sprites) patterns. - AddedProject-wide style preset (
UniTextSettings.GlobalStylePreset): aStylePresetconfigured once in Project Settings → UniText applies to every component automatically. A new per-componentUseGlobalStylePresettoggle (default on) opts a single component out — useful for debug overlays or technical text where global markup rules would interfere. LocalStylesand localStylePresetsregister first and keep override priority on parse-rule conflicts. - Added
UniTextBase.BeforeProcessstatic event: fires before any text processing in the canvas-update cycle, alongside the existingMeshAppliedandAfterProcess. - Added
InlineTagRule: tag rule with HTML void-element semantics — every<tag>/<tag=value>is treated as a single self-closing insertion, the/>shorthand is no longer required, and stray closing tags are silently stripped. Used by the new Inline Sprite and Inline Object presets. - Added
StylePresetruntime mutation API:AddStyle,RemoveStyle,RemoveStyleAt,ClearStyles, plus an always-onChangedevent (was editor-only). Components subscribed to the preset rebuild on the next frame. - AddedCustom modifiers automatically appear in the inspector preset picker: any concrete
BaseModifiersubclass without a curated entry is listed alphabetically under a new Custom group, paired with a full-textRangeRulefor immediate use. - AddedPer-modifier accent colours in the inspector: each modifier type gets a stable colour used for its icon tint, the colored label in style entry headers, and the preset toggle button background.
- AddedUnified rounded toggle-button style in the inspector with hover outline — alignment buttons, preset toggles,
Auto Size,Word Wrap,Use Global Style Preset, and the Expand / Highlight / Rendered toggles now share one visual; the Rendered toggle's accent colour reflects the text-override state (green for Resolver, orange forSetText).
- Changed
UniTextSettings.Changedis nowAction<string>(breaking): the payload is the property name that changed (nameof(Gradients),nameof(GlobalStylePreset),nameof(Language),nameof(Dictionaries)) or the newUniTextSettings.Allsentinel when the whole asset is replaced viaSetInstance. Filter with the newUniTextSettings.Affects(changed, interested)helper; existing handlers must add astringparameter. - Changed
IGradientProvidernow derives fromINamedCatalog<UniTextGradients.NamedGradient>(breaking for custom providers): replaceTryGetGradient(string, out Gradient)withTryGet(string, out UniTextGradients.NamedGradient)— the entry exposes thegradientfield. Callers that read from aUniTextGradientsasset directly are unaffected. - Changed
StylePreset.stylespublic field removed (breaking): use the newStylesread-only list and theAddStyle/RemoveStyle/ClearStylesmutation API. - ChangedModifier configuration fields converted to properties (breaking):
OutlineModifier.fixedPixelSize,ShadowModifier.fixedPixelSize,ExtrudeModifier.steps/bevel/fixedPixelSize,ListModifier.markerPlacement/bulletMarkers/orderedStyles,CompositeModifier.modifiers, andMaterialModifier's render order / sort index / emoji material / quad padding fields are no longer public — assign through the matching PascalCase property (FixedPixelSize,Steps,MarkerPlacement,RenderOrder, etc.) so the setter requeues the right rebuild stage. Serialized values migrate automatically; only direct field access from runtime code needs updating. - ChangedNested list items indent under their own parent marker, not under the widest sibling: when a list mixes marker widths between siblings (e.g. an ordered sublist nested under one bullet but not another), the nested column shifts to match its parent's marker width instead of the maximum across the entire list. Matches Google Docs / MS Word;
Outsideplacement and level-0 unchanged. - ChangedInline Object and Inline Sprite presets use
InlineTagRule—<obj=name>and<sprite=name>no longer need the/>suffix to self-close. - Changed
GlobalSettingsGradientProviderrebuilds only when the project's gradient asset reference or its entries change; unrelatedUniTextSettingsedits no longer trigger a gradient rebuild.
- Removed
GradientNotifierstatic class (AnyChangedevent,NotifyChangedmethod): replaced by per-instanceINamedCatalog<TEntry>.Changedevents on each provider. Custom gradient providers should raise their ownChangedwhen their resolution result changes.
- Fixed
GradientModifier.Providersetter ignored the catalogChangedsubscription: assigning a new provider at runtime left edits to the new provider unnoticed and kept the old provider driving rebuilds.
2.1.10
2026-05-08
- AddedWebGL builds now match the active Emscripten toolchain: the package ships native WebGL binaries built for legacy Emscripten 3.1 (Unity 2021–6000.4) and modern Emscripten 4.0 (Unity 6000.5+), each in default and WebAssembly 2023 long-jump variants, and the editor picks the right one automatically based on Unity version and the WebGL
wasm2023PlayerSetting. - Added
ListMarkerPlacementenum andListModifier.markerPlacementfield: pick betweenInside(default — marker takes inline space at the line start, content shifts past it; matches Google Docs, MS Word, Discord) andOutside(marker right-aligned to a fixed content column, hangs into the leading margin if wider; equivalent to CSSlist-style-position: outside), direction-aware in both LTR and RTL paragraphs.
- Changed
ListModifier.indentPerLevelfield removed (breaking — serialized values are dropped by Unity): the per-nesting-level indent step is now derived from the widest marker in the list instead of a fixed0.55em × fontSize, so columns auto-fit any marker style without manual tuning. Visible difference is at nested levels — wider for lists with multi-digit numbers or long bullets, narrower for short ones; level-0 layout is unchanged. - Changed
<indent>now indents from the tag opening, not just from the next line: when the tag opens mid-line, content following the open boundary visibly shifts within the current line; previously only wrapped lines whose first codepoint sat inside the tag were pushed.
- FixedMarkdown list items folded a non-indented following paragraph: a plain-text line at the same or lower indent than a
-/*/+/numbered item was absorbed into the previous list item instead of breaking out into its own paragraph. - Fixed
CreateAssetWithContentobsolete-API warning on Unity 6000.4+: creating a custom UniText shader fromAssets > Create > UniText > Custom Shaderraised a deprecation warning on Unity 6000.4+.
2.1.9
2026-05-07
- Added
<br>hard line break (LineBreakParseRule, standalone — register without a modifier): forces a line break wherever<br>,<br/>, or<br />appears in the source, with HTML void-element semantics (no closing tag, no nested content); the new line keeps the surrounding paragraph's direction, alignment, and styling. - Added
IndentModifier(default tag nameindent): adds left indent to every line whose first codepoint falls inside the tagged range, acceptingpx,em,%(of the host RectTransform width, matching CSStext-indentsemantics), and signed deltas; nested or overlapping tags compose additively like CSSmargin-left.
2.1.8
2026-05-06
- Added
UniTextUnpackEffectColor(inUniText_Custom.cginc): decodes aColor32packed byEffectPacking.PackColorfrom a UV channel with the correct sRGB-to-linear conversion for the active color space — custom material shaders that read effect colors should call it instead of unpacking by hand.
- FixedEffect colors looked washed out in Linear color space: outline, shadow, extrude, and other effect-modifier colors rendered noticeably brighter than the face text in projects using Linear rendering.
2.1.7
2026-05-02
- FixedFamily emoji and other ZWJ sequences misplaced in RTL paragraphs: parts of multi-glyph emoji (e.g. the children in 👨👩👧👦) drifted away from the main composition when the surrounding text was Arabic or Hebrew, while the same emoji rendered correctly in LTR text.
2.1.6
2026-04-30
- FixedText inside
RectMask2Dclipped off too early: a UniText whose glyphs extended past its RectTransform (long words without word wrap, outline / glow, modifier offsets) disappeared as soon as the rect itself left the mask, even though the rendered text was still inside the clip area.
2.1.5
2026-04-29
- Added
UniTextWorld.RaycastTarget(defaulttrue, inspector + property): turn off on purely decorative world-space text and the camera'sUniTextWorldRaycasterskips it entirely, mirroring CanvasGraphic.raycastTarget. - AddedOne-time warning when an interactive
UniTextWorldplays in a scene without aUniTextWorldRaycaster: instead of pointer events silently doing nothing, a single Console warning points at the camera that needs the raycaster (or atRaycastTarget = falsefor decorative text). - Added
UniTextBase.CollectRangeEntries(int, int, PooledList<LineRangeEntry>)+ publicLineRangeEntrystruct: one entry per contiguous glyph run within a line for a cluster range, with X clamped to the line's visible content extent — usable by custom modifiers and tools that need glyph-accurate spans, not just bounding rects. - Added
TextLine.glyphStart/glyphCount/widthPx/IsRtl(public): the positioned-glyph range and mesh-local content width are now exposed on each line for custom modifiers reading layout output, along with a paragraph-direction flag from the BiDi level. - Added
CanvasHighlightRendererandWorldHighlightRendererare now subclassable (public): plug a custom Canvas-side or world-space highlight visual without reimplementing the lifecycle. - AddedType-safe per-backend
TextHighlighterextension points: subclasses now overrideCreateHighlightRenderer(UniText, ...)and / orCreateHighlightRenderer(UniTextWorld, ...)to plug a custom visual on the chosen backend; subclassingDefaultTextHighlighterkeeps its click / hover / selection logic and only swaps the visual.
- Changed
UniTextBase.CreateHighlightRenderer(string, HighlightOrder)removed (breaking for custom highlighter authors): the abstract owner-side hook is gone — implement the typedTextHighlighter.CreateHighlightRenderer(UniText, ...)/CreateHighlightRenderer(UniTextWorld, ...)overloads instead, and call the protected untypedCreateHighlightRenderer(name, order)from event handlers. - Changed
TextHighlighter.OnSelectionChangedremoved (breaking for custom highlighter authors): drive selection visuals from your own state —DefaultTextHighlighter.SetSelectionshows the intended pattern. - Changed
GameObject > UI (World) > UniText > World Textno longer auto-addsUniTextWorldRaycastertoCamera.main: pick the camera explicitly; the new in-scene warning will tell you when it's missing. - ChangedDouble-line decoration:
<u double>/<s double>now renders each sub-line at the full requested thickness with a same-thickness gap (was: 35% / 30% / 35% summing to the requested thickness), making double underlines and strikethroughs noticeably bolder. - ChangedUnderline / strikethrough end-caps scale with the line's thickness instead of the underscore-glyph height: thinner lines get proportionally narrower caps for cleaner edges; thick lines keep close to the previous look.
- FixedAutoSize text shrunk and didn't grow back when the rect grew taller: after the shrink-to-fit pass reduced the effective font size to fit the height, increasing the rect's height (without changing the width) left the text shrunken until the width changed.
- FixedThick underlines / strikethroughs clipped at the top and bottom edges: when the requested line thickness exceeded the underscore glyph's natural rendered height, SDF sampling fell off the glyph and lost ink near the top / bottom of the line; the sampled region now grows with the requested thickness.
- FixedDotted and dashed underlines / strikethroughs drew a partial last mark past the line end: the pattern loop now stops at the last mark that fits entirely within the segment.
2.1.4
2026-04-29
- AddedUnderline / strikethrough styles:
UnderlineModifierandStrikethroughModifieraccept a 5-field parameter — thickness (em or px), offset (em or px), style (solid,double,dotted,dashed), skip-ink (line breaks around descenders like g, j, p, q, y), and overlay (line draws above the text instead of behind it); bare<u>/<s>still defaults to a solid line at the font's metrics. - AddedScene Visibility opt-out: a Scene view overlay and
Tools > UniText > Respect Scene Visibilitymenu toggle whether hiding a UniText / UniTextWorld GameObject in the Hierarchy clears its rendered text (default: on; per-developer, stored inEditorPrefs). - Added
UniTextMeshGenerator.EffectPass+currentEffectPass(for custom effect modifiers): a modifier can place its duplicate quads above (PostFace) or below (PreFace) the face of the current glyph, so e.g. an outline modifier draws around an overlay decoration line on top of the text rather than behind it. - Added
UniTextMeshGenerator.isVirtualGlyph(for custom modifiers): the per-glyph callback now fires for modifier-injected quads (decoration lines, kashida, list markers); read this flag to skip them when only real shaped glyphs matter. - Added
UniTextMeshGenerator.QueueEffectTriangle+RequestBandUpgradeIfNeeded(for custom modifiers that emit their own quads): public helpers to route effect triangles through the shared pre/post-face buffer and to request a wider SDF tile for the current quad without duplicating internal logic. - Added
LineRenderHelper.DrawDot(for custom decoration modifiers): emits one bullet-shaped dot quad sampled from the font's bullet glyph (U+2022), with a stretched-underscore fallback when the font has no bullet. - Added
UniText/Lit/SDFandUniText/Lit/Emojinow render under URP: world-space lit text works in Universal Render Pipeline projects from URP 12 (Unity 2021.3 LTS) through URP 17 (Unity 6), receives main-light shadows and additional-light shadows, and uses Forward+ cluster lighting on URP 14+. - AddedLit shaders cast shadows: world-space text using
UniText/Lit/SDForUniText/Lit/Emojinow contributes to shadow maps in both Built-in and URP — SDF silhouette is driven by glyph dilate (effect-mode outlines also cast their inflated shape), and emoji uses bitmap alpha with the new_ShadowCutoffmaterial property. - AddedLit shaders react to nearby point and spot lights: additional non-important point/spot lights now affect world-space lit text in both pipelines (up to 4 vertex-evaluated in Built-in; per-pixel with shadow attenuation in URP).
- Changed
UniTextMeshGenerator.Currentremoved (breaking for custom modifiers): replace with the per-component instanceuniText.MeshGenerator. - Changed
UniTextMeshGenerator.onAfterPagesplit (breaking for custom modifiers) intoonMainPassComplete(emit decoration geometry — also runs through the per-glyph pipeline) andonMainPassFinalize(effect modifier flushes); subscribe to whichever your previous handler was for. - Changed
LineRenderHelper.DrawLinesignature (breaking for custom decoration-line modifiers): now takes the generator, cluster, UV cap range, and an explicit thickness override; color is no longer a parameter — it flows through the per-glyph color / gradient / effect pipeline.
- FixedParameter field reset when switching the inspector between objects sharing the same Style layout: when two assets or components each had a Style at the same index (e.g. a
StylePresetand aUniText), switching selection between them reset the newly-selected object's parameter field to the modifier's defaults. - Fixed
<b>/<i>/<var>ignored the family chosen byFontModifier: combining<font=X>with<b>,<i>, or<var>resolved the bold/italic face or variable axis from the fallback family instead of the family named byFontModifier, so e.g.<font=Roboto><b>could render Roboto Regular instead of Roboto Bold. - Fixed
UniTextWorldreported infinite mesh bounds: every world-space text shard reported a 2 km axis-aligned bounding box, breaking frustum culling, shadow caster volumes, andRenderer.boundsqueries; bounds are now computed from the actual mesh vertices in each shard. - Fixed
UniTextWorldignored GameObject Layer: world-space text drew through every camera regardless of culling masks, because the batcher merged all components into one shared layer; the batch now keys on the component's Layer (and re-routes when the Layer changes at runtime), so cameras honor their culling mask. - FixedUnderline, strikethrough, and Arabic kashida ignored per-glyph effects: gradient, outline, shadow, and custom-material modifiers applied to text but skipped its decoration lines and kashida elongation; decoration geometry now runs through the same per-glyph pipeline and picks up all active modifiers uniformly.
2.1.3
2026-04-27
- Added
ExtrudeModifier: adds a 3D extrude / bevel stack behind the text with a per-step color gradient from near to far, configurable offset, dilate, and softness; an optional bevel mode adds intermediate side-faces for chamfered depth. Step count and bevel toggle live on the modifier; tag parameter format:offsetX,offsetY,#nearColor,#farColor,dilate,softness. - Added
EffectModifierper-layer flush hooks (for custom multi-layer effect subclasses):ApplyOwnRequestsis nowprotected virtualandAppendSharedEffectQuadisprotected static, so a subclass can buffer its own per-layer requests and flush them in painter order across all glyphs instead of the default per-glyph order.
- Changed
EffectPacking.PackColorreturnsVector2(breaking for custom effect modifiers and shaders): packed color now occupiestexcoord2.yandtexcoord2.z, and custom shaders must callUnpackColor(input.texcoord2.y, input.texcoord2.z)— the single-floatUnpackColor(float)overload is gone. - ChangedColor alpha is composited with the component's base alpha:
<color=#RRGGBBAA>ranges, gradient stops, and underline / strikethrough colours now multiply their alpha with the component alpha instead of discarding it, so<color=#FF000080>renders at 50% opacity (was: forced to component alpha). Use a fully opaque parameter to restore the previous look. - Changed
LineHeightModifier: single value parameter, no mode: the inspector now shows oneValuefield, and<lh=N>always sets line height. Existing<lh=h,N>markup still parses unchanged; existing<lh=s,N>parses but now sets height — use<lh=+N>for the additive equivalent. - Changed
Glyph Diagnosticmenu moved: now underTools > UniText > Glyph Diagnostic(was top-levelUniText > Glyph Diagnostic).
- FixedOutline and shadow color randomly tinted on some GPUs: the previous color packing produced NaN/Inf bit patterns that some drivers canonicalize at the vertex–fragment interpolator boundary, randomly altering the green channel as colors crossed certain thresholds.
- FixedMultiple
GradientModifierinstances on one component overwrote each other: each instance kept a private 1-based gradient list and stomped the shared per-codepoint index buffer, so the second modifier silently replaced the first one's gradient assignments. - FixedParameter field stuck on stale values after changing the modifier type: switching a
Style'sModifier(or a child ofCompositeModifier) in the inspector now resets the parameter field to the new modifier's defaults instead of keeping the previous modifier's text.
2.1.2
2026-04-26
- Added
UniTextBase.Animatedevent: raised after Unity Animator applies animated property values to aUniText/UniTextWorld; modifiers with their own animatable fields can subscribe, diff their state, and callSetDirtywith the matchingUniTextDirtyFlags. - Added
AnimationHandlerBase<T>: public base class for extending the built-in Animator diff with subclass-specific animatable fields when authoring a customUniTextBasesubclass.
- FixedUnity Animator did not update rendered text: animating
fontSize,color,wordWrap,autoSize,minFontSize/maxFontSize,baseDirection,horizontalAlignment/verticalAlignment,overEdge/underEdge,leadingDistribution— and onUniTextWorldalsosortingOrder/sortingLayerID— silently had no visual effect.
2.1.1
2026-04-26
- Added
IGradientProviderwith three built-in implementations —GlobalSettingsGradientProvider(default, readsUniTextSettings.Gradients),AssetGradientProvider(per-modifier asset reference),InlineGradientProvider(inline list edited on the modifier itself); pick the source for eachGradientModifierfrom the inspector. - AddedLive gradient preview in the
GradientModifierparameter dropdown: each row shows the actual gradient swatch on the right and reflects the provider currently assigned to that modifier, not just the project-wide settings. - Added
GradientNotifier: staticAnyChangedevent raised when any gradient source visible toGradientModifieris edited (asset, inline list, or a custom provider invokingNotifyChanged); affected text rebuilds on the next frame without manual refresh. - AddedPublic Unicode character properties for modifier / parse-rule authors:
UnicodeData.GetSimpleUppercase/GetSimpleLowercase/GetSimpleTitlecase,GetGeneralCategory(+ publicGeneralCategoryenum),GetScript,IsExtendedPictographic/IsEmojiPresentation/IsEmojiModifierBase,IsDefaultIgnorable— backed by bundled UCD tables and identical across Mono, IL2CPP, and standard .NET. - Added
ParameterOption+ContextualParameterOptionsProvider: extension API for[ParameterField("enum:@key")]dropdowns — options can carry a display label, a per-row preview decorator, and a description, and can be derived from the owning modifier instance.
- Changed
UppercaseModifier/LowercaseModifier/SmallCapsModifierresolve case via the bundled Unicode case mapping table instead ofchar.ToUpper/LowerInvariant; behavior is identical across Mono, IL2CPP, and standard .NET runtimes.
- FixedEmoji rendered as
.notdefinside aFontModifierrange: emoji codepoints in a range covered byFontModifierwere forced through the chosen text font, which has no emoji glyphs; emoji now always resolve to the emoji font regardless of any explicit font override. - Fixed
FontModifierdid not fall back to the FontStack chain: codepoints not covered by the named family produced.notdefinstead of falling through the standard fallback chain (as the docs already promised). - Fixed
UppercaseModifierskipped Greek final sigma (U+03C2 ς): the last character of words like "πόνος" was left lowercase due to a runtime gap in Mono's case tables.
2.1.0
2026-04-25
- AddedLanguage-aware shaping (BCP 47 + OpenType
locl): fonts with language-specific glyphs (pan-CJK like Noto Sans CJK / Source Han Sans) now render the correct regional forms. Apply per-range withLanguageModifier, per-component viaUniText.Language, or project-wide viaUniTextSettings.Language. - Added
FontModifier: override the font on a text range by referencing aFontFamily.namefrom the component'sUniTextFontStack. A matched family wins over bothpreferredLanguageselection and the default fallback chain; the normal chain still kicks in for codepoints the chosen family can't render. Unknown names log a one-time warning. - AddedPer-family language hint:
FontFamily.preferredLanguage— one font stack can hold region-specific cuts (SC/TC/JP/KR) and pick the right one automatically from the active language. - AddedNamed font families:
FontFamily.namelets you address a family directly fromFontModifieror code instead of relying on fallback order. - AddedWorld-space batcher shard size:
UniTextSettings.WorldBatcherShardTargetVertexCountto tune batching granularity vs. rebuild cost for dense world-space scenes. - AddedCustom sub-mesh emission: a modifier can now emit its own geometry with a custom material/atlas that renders
Under,Above, or alongside the base text, ordered by asortIndex— viaUniTextMeshGenerator.onCollectSubMeshesandUniTextRenderData. - AddedQuad expansion API:
UniTextMeshGenerator.ExpandQuad+faceBaseIdx+DefaultSdfPadding— a supported way for effect modifiers to grow a glyph quad so wide outlines / fake-bold / soft shadow don't clip at the quad edge. - AddedText-model properties on
UniTextBase: four zero-alloc views covering the full pipeline from authored text to what's drawn. - AddedText resolver hook (
IUniTextResolver+UniTextBase.TextResolver): override a component's source text (localization preview, template expansion, key-to-string lookup) without writing to the serializedtextfield, so scenes and prefabs don't get marked dirty. - Added
SetText(ReadOnlyMemory<char>)/SetText(string): assign text at runtime without writing to the serialized field and without marking the scene/prefab dirty. - Added
UniText.Languageproperty: one-line way to apply a BCP 47 language to the whole text from code, without building a style manually. - AddedClick / hover / selection highlighting on
UniTextWorld: theHighlighterslot now lives onUniTextBaseand works unchanged on both Canvas and world-space text. - AddedCustom highlighter API:
TextHighlightersubclasses can now target both Canvas and world-space text by requesting a backend-agnostic surface —owner.CreateHighlightRenderer(name, HighlightOrder.Behind | Above)returns aTextHighlightRendererwithColor,SetRects(...),Clear(),Destroy(). - AddedStyle/modifier query and mutation API on
UniTextBase:HasModifier<T>(),TryGetStyle<T>(),SetWholeText<T>(parameter),ClearWholeText<T>(),ToggleWholeText<T>(parameter),GetWholeTextParameter<T>()and non-genericTypeoverloads. Replaces the manualnew Style { Rule = new RangeRule { data = ... }, Modifier = ... }boilerplate for programmatic styling. - Added
UniTextWorldpublic events + active registry: staticActivated/Deactivated, per-instanceRenderDataAvailable/RenderDataCleared/SortingChanged/ParentChanged, and aUniTextWorld.Activelist of currently enabled instances. Observe world-space text state without scene scans. - AddedClick / hover on
UniTextWorld: add aUniTextWorldRaycastercomponent to aCameraand world-space text receives the same pointer events that worked on Canvas —RangeClicked/RangeEntered/RangeExited, link and hashtag events. No per-text colliders needed. OptionalBlockingObjectssetting to respect 2D/3D physical geometry as occluders. - Added
UniTextin Add Component menu: discoverable underUI (Canvas) > UniTextin the inspector's Add Component dropdown. - Added
MaterialModifier: apply a customMaterialto a text range. Shader gets the glyph atlas as aTexture2DArray, two constant per-text UV4 channels (ConstantUv2/ConstantUv3) for runtime-animated shader params, and an optional per-glyph UV writer for staggered effects. Three compose modes —Replace(hide the base text on the range),Over,Under. Parameter is an optional tint color. SeparateemojiMaterialslot for emoji glyphs inside the range. - AddedProtection parse rules: three standalone rules that shield content from any other parse rule (no pairing modifier needed) —
NoparseTagRule(<noparse>…</noparse>, forgiving close),CodeSpanRule(balanced backtick runs per CommonMark §6.1:`x,`x,`x`), andBackslashEscapeRule(\*,\[, …, full CommonMark ASCII punctuation set). - AddedStandalone parse rules: a rule can be registered on
UniTextwithout a paired modifier (opt-in viaIParseRule.IsStandalone) — it applies its effect on its own. Used by the three protection rules above. - Added
Stylestatic builders:Style.WholeText(modifier, parameter),Style.Range(modifier, start, end, parameter),Style.Tag(modifier, tagName, defaultParameter)— replace thenew Style { Modifier = ..., Rule = new RangeRule { data = new() { ... } } }boilerplate when building styles in code. - Added
RangeEx.WholeText/RangeEx.IsWholeText(...): canonical".."constant and a predicate that accepts any equivalent syntactic form ("..","..^0","0..") — useful when building rules from user input. - Added
SubMeshModifierabstract base class: base class for writing your own modifiers that produce a separate sub-mesh with its own material (the same surfaceMaterialModifieris built on). - AddedCustom shader authoring:
Assets/Create > UniText > Custom Material Shadermenu scaffolds a new shader pre-wired forMaterialModifier(usesUniText_Custom.cginc, binds the glyph atlasTexture2DArray). Three example shaders ship as starting points (Dissolve, Hologram, Rainbow). - AddedNoise generator:
Tools > UniText > Noise Generatorwindow produces seamless grayscale value / FBM PNG textures (64–1024 px, configurable seed / frequency / octaves / lacunarity / gain / invert / tileable). Used by the example shaders; available for any procedural need. - AddedLit shaders for world-space text:
UniText/Lit/SDFandUniText/Lit/Emojipick up ambient + a single directional light + fog, suitable forUniTextWorldin a 3D scene. - AddedDefault materials: ready-to-use
UniTextLit,UniTextEmojiLit,UniTextDisolve,UniTextHologram,UniTextRainbowmaterials inDefaults/Materials/(drop on aMaterialModifieror assign as the material of aUniTextWorld). - Added
GameObject > UI (World) > UniText > World Textmenu item: creates a ready-to-goUniTextWorldobject and auto-adds aUniTextWorldRaycastertoCamera.mainso pointer events work out of the box. - AddedBasic Usage sample extended: new Language and Font sections, plus a bundled Source Han Sans subset (
Fonts/SourceHanSans-Demo.otf, ~96 KB, SIL OFL 1.1) that actually shows CJK regional-glyph differences in the Language example. - AddedLanguage APIs (public):
LanguageRegistry.Register/GetHandle/GetTag,LanguageMatching.Matches,Shaper.ShapeInto(..., IntPtr language)overload,HB.LanguageFromString/HB.SetLanguage/HB.ShapeRun(..., IntPtr language, ...),UniTextFontStack.FindFontForCodepoint(uint, string preferredLanguage, ...),UniTextFontProvider.FindFontForCodepoint(int, byte language)— for code that drives shaping manually. - Added
UniTextFontStack.TryGetFamilyByName(name, out family)/UniTextFontProvider.TryGetFontIdByFamilyName(name): resolve aFontFamily.nameto a family or fontId at runtime. - Added
SharedFontCache.TryGet/Setlanguage overloads: per-codepoint font-cache key now includes the active language, so the same codepoint can cache different results under different language tags. - Added
UniTextBuffers.PrepareStartMargins(): for modifier authors writing start-margin values (list indentation etc.) — lazily allocates the buffer to fit the current codepoint count. - Added
PooledBuffer<T>.ClearAll()/PooledArrayAttribute<T>.ClearAll(): clear the entire backing array (not just the[0..count)prefix) — matches the modifier-attribute usage pattern where the buffer is read at arbitrary indices. - Added
UniTextMaterialCache.Highlight: shared flat-colour transparent material used for range highlights (exposed for custom highlighter renderers). - Added
Run.language/ShapedRun.language(public struct fields): carries the language-registry index through the pipeline. - AddedProject-wide language in Project Settings: a Localization section in the UniText Settings panel edits
UniTextSettings.Languagewithout writing code. - Added
Tile Size Offsetper-font setting (UniTextFont inspector): nudge the auto-classified SDF atlas tile size up or down by ±2 steps to force higher quality or save atlas memory; ignored on glyphs that have an explicit per-glyph tile override.
- ChangedFaster first-frame glyph generation: SDF/MSDF preparation scales much better with glyph complexity — the internal contour-overlap check is now linear instead of quadratic in the number of curve segments per glyph. Biggest wins on CJK, decorative, and symbol fonts.
- ChangedInspector modifier/rule picker: the popup now sizes to its content and resizes when groups expand/collapse, instead of truncating at 15 items.
- ChangedFontStack inspector (collapsed family row): shows
nameandprimaryinline so you can rename / swap fonts without expanding the foldout. - ChangedDirty flags / render mode enums lifted to top level (breaking):
UniTextBase.DirtyFlags→UniTextDirtyFlags,UniTextBase.RenderModee→UniTextRenderMode. Code referencing the old nested enums will not compile. - Changed
CleanTextreturn type (breaking):string→ReadOnlySpan<char>. The backing buffer is pooled and may be rewritten on the next rebuild; copy vianew string(span)if you need a stable string. - Changed
Textgetter semantics (potentially breaking): always returns the serialized authored value, even when a buffer-basedSetTexthas overridden the runtime text. Read the runtime-assigned text viaRawText(orRenderedTextif a resolver is in play). - Changed
TextHighlighter.Initialize(UniText)→Initialize(UniTextBase)(breaking for custom highlighter subclasses). Theownerfield type switched fromUniTexttoUniTextBasefor the same reason — highlighter now works on both Canvas and world-space text. - ChangedPer-tag parse-rule classes are now
internal [Obsolete](breaking if referenced in code):BoldParseRule,ItalicParseRule,ColorParseRule,SizeParseRule,UnderlineParseRule,StrikethroughParseRule,CSpaceParseRule,LineSpacingParseRule,LineHeightParseRule,OutlineParseRule,ShadowParseRule,ObjParseRule,EllipsisTagRule,UppercaseParseRule,GradientParseRule,LinkTagParseRule. Existing serialized assets still deserialize; new code should useTagRule(directly or viaStyle.Tag(modifier, "name")). - ChangedCustom
EffectModifiersubclasses (breaking): the extension hook is nowOnGlyphEffect()+EnqueueEffectQuad(...)instead ofRecordEffectGlyph(...), and theHasVertexShifts()override is gone. Built-in outline/shadow are unchanged for consumers; this only matters if you wrote your own effect subclass.
- FixedAuto-size on
UniTextWorld:autoSizeon world-space text silently fell back tomaxFontSize— the size-fitting step was Canvas-only. It now runs for world-space components too. - Fixed
UniTextWorldsorting vs. other renderers: world-space text was batched into one mesh regardless of each instance's sorting layer/order, so it rendered in front of or behindSpriteRendererand other renderers as one block instead of interleaving per-instance. The batcher now groups by(material, SortingLayer, OrderInLayer, SortingGroup), so each group becomes its own draw with the correct sorting. - FixedOutline / shadow artifacts on emoji:
OutlineModifierandShadowModifierapplied their effect passes to emoji glyphs too, which rendered color bitmaps through an SDF effect shader and produced garbage. Both now skip color bitmap glyphs.
2.0.15
2026-04-20
- FixedWebGL emoji disappearing after text change: Reusing the same emoji in a later text update left a transparent gap where the emoji should be rendered.
- FixedWebGL emoji missing when not at the start of text: Emoji appearing after any preceding characters — including dual-presentation symbols like ⬅, ➡, ❤, ☀ — were not rendered and took no layout space.
- Fixed
<size>tag spreading letters apart at non-100% scales: Letters inside a size-scaled range kept their original spacing and bearings while only the glyph quads shrank or grew, so small scales (e.g.<size=10%>) produced tiny letters scattered across the original word width instead of a proportionally compact word. - FixedDiacritics detached from base letter inside
<size>: Arabic and other combining marks floated far from their base glyph when a per-range size scale was applied, because mark offsets were not scaled along with the base advance.
2.0.14
2026-04-18
- FixedRTL list marker position unstable: Bullet and number markers in right-to-left lists (Arabic, Hebrew) shifted unpredictably when the item text changed and could render in the wrong position depending on the first character of the line.
2.0.13
2026-04-18
- ChangedTemporarily disabled native atlas upload path: Atlas texture updates fall back to the standard upload to avoid crashes on macOS and glyph corruption seen in 2.0.0–2.0.12. Native path will return once stabilized.
2.0.12
2026-04-17
- FixedKorean text breaking mid-word: The line breaker could split Korean (Hangul) text between adjacent syllables at optional break points, producing broken line wraps inside words.
- FixedSDF/MSDF artifacts inside glyphs with holes: Bridge regions between overlapping contours (letters such as O, A, B, D, e) produced false distance gradients, visible as faint streaks or specks inside the hollow areas of the glyph.
- Fixed
enableWordWraptoggle not re-flowing text: Switching the word-wrap setting between updates could reuse the cached line layout from the previous mode, leaving text wrapped (or unwrapped) incorrectly until another layout-invalidating change.
2.0.11
2026-04-15
- FixedEmoji ignoring RectMask2D soft edges: Emoji glyphs were clipped with a hard edge under a
RectMask2Dwith non-zero softness, while surrounding UI elements faded smoothly across the same boundary.
2.0.10
2026-04-15
- FixedStyle preset effects leaking onto other text: Modifiers inside a
StylePreset(bold/italic/underline used viaCompositeModifier) kept their attribute flags and event subscriptions between text updates, so italic, underline, and bold visibly appeared on unrelated characters after switching to text that did not use the preset tags.
2.0.9
2026-04-15
- FixedUnderline/Strikethrough skipping lines at small font sizes: At Font Size ≤3.6, every other line rendered without its underline or strikethrough — lines 1 and 3 got a line, lines 2 and 4 were bare.
- FixedUniText Text/Button created outside prefab in Prefab Mode: Right-clicking empty space in the Hierarchy while editing a prefab placed the new
UniText - TextorUniText - Buttonunder a Canvas in the open scene instead of inside the prefab.
2.0.8
2026-04-14
- Added
ParameterReaderexposed as public API: Custom modifier authors can now parse tag parameters (floats, unit floats, colors, tokens) using the same locale-safe reader as built-in modifiers. - Added
GlyphAtlasread-only introspection API: The SDF and MSDF atlases are now reachable viaGlyphAtlas.GetInstance(RenderMode), withTryGetEntryreturning a publicGlyphEntry(page index, encoded tile, glyph metrics, pixel size). Key-building helpersMakeKey,DefaultVarHash,ComputeVarHash48, theTileSizeFromEncodeddecoder, and constantsPad/PageStride/DefaultBandPixelsare also accessible for tooling and custom renderers.
- ChangedEditor menus reorganized:
Tools/UniText ToolsandTools/UniText Migrationconsolidated under theTools/UniText/submenu. GameObject creation moved fromGameObject/UI/UniText - Text|ButtontoGameObject/UI (Canvas)/UniText/Text|Button.
- FixedTrailing empty line missing from range bounds:
GetRangeBoundsskipped the empty line produced by a trailing newline (e.g."abc\n"), so selection highlighting and link/hashtag bounds covering that line returned no rectangle. - FixedStencil material showing wrong atlas texture: Text under a
Maskcould render with a stale or mismatched atlas texture after an atlas resize, especially when a renderer group mixed text and emoji glyphs. - FixedAtlas shrink corrupting glyphs: Trimming unused atlas pages used a mixed GPU/CPU copy path that could leave stale slice data and drop or corrupt glyphs after the atlas compacted.
2.0.7
2026-04-08
- FixedFont Subsetter dropping OpenType layout tables: Subset fonts lost all GSUB/GPOS/GDEF/kern tables, breaking contextual shaping (Arabic connected forms, Indic conjuncts, ligatures, kerning).
- FixedAndroid 16KB page size compatibility: Native GPU library failed to load on Android 15+ devices with 16KB memory pages.
2.0.3
2026-04-07
- AddedRuntime Style Preset API:
AddStylePreset(),RemoveStylePreset(), andClearStylePresets()methods for assigning shared style presets to text components through code.
- FixedText invisible after reparenting out of a Mask: Moving a UniText object from under a
Maskat runtime viaSetParentleft stale stencil material, causing text to disappear. - FixedEditor errors when reverting a prefab with nested UniText: "Revert All" on a prefab containing a nested UniText component produced
MissingReferenceExceptionfor destroyedCanvasRenderer. - FixedClick events not reaching parent Button: UniText nested inside a Button blocked
OnPointerClickfrom reaching the parent. Now pointer events propagate to the parent unless an interactive range (link, hashtag, etc.) is clicked. - FixedRTL list marker offset on wrapped lines: List markers shifted closer to text when an RTL line was wrapped by the line breaking algorithm.
2.0.2
2026-04-06
- FixediOS emoji sequences not combining: Emoji with skin tone modifiers, ZWJ sequences, and flag sequences rendered as separate glyphs on iOS. Fixed by shaping emoji through CoreText with
kCTTypesetterOptionAllowUnboundedLayout. - Fixed
<lh>delta units: Delta values (<lh=+5px>) were treated as absolute instead of adding to the default line advance. - Fixed
<lh>overridden by globalMinAdvance: Custom line heights set by<lh>were silently replaced by the global minimum advance. Now only applies to lines with default height.
2.0.1
2026-04-04
- FixedGPU texture upload on Vulkan (Windows): Native GPU upload path was disabled for Vulkan, falling back to
Texture2D.Apply(). - FixedGlyphAtlas resize crash: Atlas resize with 1 slice caused Unity to collapse
Texture2DArrayintoTexture2D, breaking native upload. - FixedGlyphAtlas resize losing glyphs: Resize used
Graphics.CopyTexturewhich could fail. Now re-uploads dirty slices via native GPU upload. - FixedUnity 2021 compatibility:
TextureCreationFlags.DontInitializePixels | DontUploadUponCreateguarded behindUNITY_2022_1_OR_NEWER. - FixedScene Visibility not hiding UniText/UniTextWorld: Eye icon toggle in hierarchy had no effect.
- FixedUniTextWorld invisible in Prefab Stage: World-space text was invisible when editing prefabs. Batcher now creates a separate instance per Prefab Stage
2.0.0
2026-04-01
- AddedGlyphAtlas (
Runtime/FontCore/GlyphAtlas.cs): SharedTexture2DArray-backed glyph atlas with two singleton instances — one for SDF (RHalf) and one for MSDF (RGBAHalf). Features adaptive tile sizes (64/128/256 based on glyph complexity), shelf-based packing within 2048x2048 pages, reference counting with LRU eviction, automatic page recycling, and atlas shrinking. - AddedSdfGenerator (
Runtime/FontCore/SdfGenerator.cs): Burst-compiledIJobParallelForthat generates single-channel SDF tiles using contour-seeded vector propagation (8SSEDT). Operates on raw quadratic Bezier curves — no bitmap rasterization. - AddedMsdfGenerator (
Runtime/FontCore/MsdfGenerator.cs): Burst-compiledIJobParallelForthat generates multi-channel SDF tiles inRGBAHalfformat. Three per-channel seed+propagate passes with tangent carry for pseudo-distance encoding, plus a fourth channel-agnostic error correction pass. - AddedSdfCore (
Runtime/FontCore/SdfCore.cs): Shared types and reference implementations of SDF/MSDF algorithms —GlyphTaskstruct (used by both generators), tile transforms, Y-monotone splitting, winding number computation, 8SSEDT propagation (with and without tangent), Newton refinement, and quadratic solver. BothSdfJobandMsdfJobinline their own copies of the algorithms for optimal Burst codegen. - AddedGlyphCurveCache (
Runtime/FontCore/GlyphCurveCache.cs): Per-font lazy extraction of glyph outlines as quadratic Bezier segments via FreeTypeOutlineDecompose. Normalizes curves to [0,1] glyph space, computes per-contour winding, runs edge coloring, and sorts segments by Y. Includes a thread-safe FreeType face pool for parallel extraction. - AddedEdgeColoring (
Runtime/FontCore/EdgeColoring.cs): Port of msdfgen'sedgeColoringSimple— assigns per-edge RGB channel masks for MSDF rendering. Detects corners via cross/dot product thresholds and cycles colors at corner vertices. Computes bisector vectors and corner flags for each segment. - AddedRenderMode enum on
UniTextcomponent:SDF(single-channel) orMSDF(multi-channel) — controls which atlas mode the component uses. - AddedSDF Detail Multiplier on
UniTextFont: Controls tile size classification — higher values force larger atlas tiles for fonts with thin strokes (e.g. calligraphic). - AddedGlyph Overrides on
UniTextFont: Per-glyph tile size overrides (Auto/64/128/256) for fine-tuning quality on specific glyphs. - AddedFontFamily struct on
UniTextFontStack:families[]array replaces old flatfonts+variantslists. Each family has aprimaryfont and optionalfaces[](bold, italic, light, etc.) with a pre-computedFontFaceLookupfor fast weight/style matching. - AddedFontFaceLookup: Sorted weight arrays, variable font slots (upright + italic), CSS §5.2 weight matching via BinarySearch. Pre-computed at initialization.
- AddedVariable font support:
VariationModifierwith<var>tag for direct axis control (wght, wdth, ital, slnt, opsz).UniTextFont.VariableAxesexposes axis metadata.IsVariableproperty. Variable font axis enumeration via HarfBuzz (hb_ot_var_get_axis_infos) and variation setting viahb_font_set_variations. - AddedThree-tier face resolution in
ResolveFontFaces(): (1) Variable font axes — if font has wght/ital/slnt, set axes directly; (2) Static font face — CSS §5.2 weight matching viaFontFaceLookup.FindFace(); (3) Synthesis — fake bold/italic buffers remain non-zero for shader-based synthesis. - Added
<b>/<i>semantic tags: Automatically resolve to variable axes when available, fall back to static faces, then to synthesis.<var>tag provides direct axis control without fallback. - AddedCSS font-weight scale for bold:
BoldModifieruses weight scale 100-900 encoded as a byte per codepoint. Smart default:max(700, baseWeight + 300). Explicit parameter:<b=500>for CSS weight 500. Fake bold applied via SDF shader dilate (UV1.y) and per-glyph advance correction using FreeType's embolden ratio (em/24). - AddedVariation run tracking:
VariationRunInfostruct andvariationMapdictionary in TextProcessor track per-run axis values.Shaper.Shape()acceptsHB.hb_variation_t[]parameter. FreeType coordinates set viaFT.SetVarDesignCoordinates(). - AddedFaceInfo auto-population (editor):
familyName,styleName,weightClass, andisItalicare automatically extracted from font data via FreeType onOnEnable/OnValidateand kept in sync. Fields are read-only in the inspector. - AddedNative variable font API: HarfBuzz axis enumeration/variation setting and FreeType Multiple Masters support (
FT.GetMMVar,FT.SetVarDesignCoordinates) inFT.csandHB.cs. - AddedWordSegmentationProcessor (
Runtime/Unicode/WordBreak/WordSegmentationProcessor.cs): Post-processes UAX#14 line breaks — dispatches contiguous SA-class script runs (Thai, Lao, etc.) to registered word segmenters. - AddedBestPathSegmenter (
Runtime/Unicode/WordBreak/BestPathSegmenter.cs): Dictionary-based best-path (maximal matching) DP algorithm — same approach as ICU Thai. InsertsOptionalbreak opportunities at word boundaries. - AddedDoubleArrayTrie (
Runtime/Unicode/WordBreak/DoubleArrayTrie.cs): Read-only compact double-array trie for fast dictionary lookup. Thread-safe after construction. - AddedWordSegmentationDictionary (
Runtime/Unicode/WordBreak/WordSegmentationDictionary.cs): ScriptableObject holding compiled trie data for a specific script. Configured viaUniTextSettings.dictionaries[]. - AddedDictionary Builder tab in UniText Tools window: Builds dictionary assets from word list text files. Supports drag-and-drop, multi-file selection, target script selection, and automatic trie compilation.
- AddedEffectModifier (
Runtime/ModCore/EffectModifier.cs): Abstract base class for modifiers that render an additional effect pass behind the face. RegistersEffectPass(apply/revert callbacks) on the mesh generator. ProvidesRecordEffectGlyph()to store per-glyph UV and offset data, andApplyToMesh()/RevertFromMesh()to write effect data to UV2 channel with vertex position offsets. - AddedOutlineModifier (
Runtime/ModCore/Modifiers/OutlineModifier.cs): Outline effect via<outline=dilate>,<outline=#color>, or<outline=dilate,#color>. Supports fixed pixel size mode. Defaults: dilate=0.2, color=black. - AddedShadowModifier (
Runtime/ModCore/Modifiers/ShadowModifier.cs): Shadow/underlay effect via<shadow=#color>,<shadow=dilate,#color>, or<shadow=dilate,#color,offsetX,offsetY,softness>. Supports vertex shifts for offset shadows and fixed pixel size mode. Defaults: dilate=0, color=black 50% alpha. - AddedEffectPacking (
Runtime/Core/EffectPacking.cs): Static utility for packingColor32into a singlefloatvia bit reinterpretation for shader unpacking. - AddedUV2/UV3 buffers on
UniTextMeshGenerator: On-demand allocation of additional UV channels for effect layer data. - AddedMulti-pass rendering in
UniText.UpdateSubMeshes: Effect passes rendered before the face pass using separate materials (Base shader). Each pass applies and reverts its mesh modifications via callbacks. - AddedUniTextMaterialCache (
Runtime/Core/UniTextMaterialCache.cs): Static cache that lazily creates and manages shared materials — SDF Face, SDF Base, MSDF Face, MSDF Base. MSDF variants use theUNITEXT_MSDFshader keyword. Subscribes to atlas texture changes and syncs_MainTexautomatically. - AddedShader references on UniTextSettings:
requiredShaders[]array stores references to Base, Face, and Emoji shaders.GetShader(int index)provides runtime access. Settings provider auto-populates these on editor load. - AddedTagRule (
Runtime/ModCore/Rules/TagRule.cs): Universal configurable tag parse rule that replaces all individual per-tag rule classes. A single sealed class with a serializedtagNamefield. SupportsdefaultParameterfor fallback values and automatic parameter merging (tag-supplied values take priority, remaining fields filled from default). - AddedMarkdownWrapRule (
Runtime/ModCore/Rules/MarkdownWrapRule.cs): Parse rule for Markdown-style symmetric wrap markers (**,*,~~,++). Configurable marker string, stack-based open/close matching, priority by marker length. - AddedSimplified TagParseRule base: Parameters are now always optional (no
HasParametervirtual). Self-closing is purely syntax-driven (<tag/>or<tag=value/>). RemovedHasParameter,IsSelfClosing,InsertStringvirtual properties. - AddedDeprecatedTagRules (
Runtime/ModCore/Rules/DeprecatedTagRules.cs): All 16 tag parse rule classes (14 old + 2 new for outline/shadow) consolidated as hidden one-liner definitions marked with[HideFromTypeSelector]for backward-compatible deserialization. - AddedSelector (
Editor/Selector.cs): Full-featured searchable popup selector with grouped mode (expandable group headers with submenu panels), flat search mode (multi-word tokenized, case-insensitive), keyboard navigation, description panels, theme-aware icons, auto-close on focus loss, and optional search field toggle. - AddedMod Register Presets: The modifier list in the UniText inspector now opens a
Selectorwith ~30 predefined presets (Bold, Italic, Outline, Shadow, Markdown variants, etc.) with icons and descriptions. Presets auto-configure both modifier and parse rule. - AddedRangeRuleDataDrawer (
Editor/RangeRuleDataDrawer.cs): Custom property drawer forRangeRule.Datathat generates structured UI for modifier parameters based onParameterFieldAttributemetadata. Supports float, int, color, bool, string, enum, and unit (px/em/%) field types. - AddedUniTextFontStackEditor (
Editor/UniTextFontStackEditor.cs): Custom inspector forUniTextFontStackwith a Font Families section — each family displayed as a foldable group with primary font, faces list, family name mismatch warnings, weight/italic labels, add/remove buttons, and drag-and-drop zone. - AddedGlyph Picker in font editor: Type text to preview glyph rendering, select individual glyphs, and add tile size overrides directly from the preview grid.
- AddedVariable Axes Info in font editor: Displays detected variable font axis metadata (tag, name, min/default/max) when a variable font is loaded.
- AddedUniTextObjectMenu (
Editor/UniTextObjectMenu.cs):GameObject/UI/menu items for creating UniText Text and Button objects. Supports prefab overrides viaUniTextSettings. Creates Canvas/EventSystem if needed. - AddedAtlas preview tabs: Font editor preview split into SDF, MSDF, and Emoji tabs. Uses a
Hidden/UniText/AtlasPreviewshader to display raw distance field textures (grayscale for SDF, RGB for MSDF) fromTexture2DArrayslices. - AddedTheme-aware editor icons:
UniTextEditorResourcesprovides tinted icon caching for dark/light theme, with per-group and per-type icon mappings. - AddedText selection highlight:
DefaultTextHighlightergains aselectionGraphicfor programmatic text selection display viaSetSelection()/ClearSelection(). - AddedParameterFieldAttribute (
Runtime/Attributes/ParameterFieldAttribute.cs): Declares modifier parameter metadata (order, name, type, default) for auto-generating editor UI. Applied to all parameterized modifiers. - AddedTypeDescriptionAttribute (
Runtime/Attributes/TypeDescriptionAttribute.cs): Human-readable description for types, shown in the Selector popup. Applied to all modifiers and parse rules. - AddedHideFromTypeSelectorAttribute (
Runtime/Attributes/TypeSelectorAttribute.cs): Hides a type from the type selector dropdown while keeping it deserializable. - Added
virtualPositionedGlyphsbuffer onUniTextBuffers: Separate buffer for glyphs injected by modifiers (ellipsis dots, list markers). Does not affect hit testing or selection. - Added
BeforeGenerateMeshevent onUniText: Raised after glyph positioning but before mesh generation, allowing modifiers to inject virtual glyphs. - Added
EllipsisModifierandListModifiernow injectPositionedGlyphentries into the virtual buffer instead of drawing directly during mesh generation. - AddedUniTextWorld (
Runtime/Core/Component/UniTextWorld.cs): World-space text rendering component. Provides the same text processing pipeline asUniText(Unicode, BiDi, shaping, line breaking, modifiers, emoji, font fallback, variable fonts) but renders via MeshRenderer + MeshFilter instead of CanvasRenderer. No Canvas required. - AddedUniTextBase (
Runtime/Core/Component/UniTextBase.cs): Extracted shared base class fromUniText— all text processing, modifier management, dirty flags, lifecycle, and parallel batch pipeline now live inUniTextBase. BothUniText(Canvas) andUniTextWorld(MeshRenderer) inherit from it. - AddedUniTextBase_Parallel (
Runtime/Core/Component/UniTextBase_Parallel.cs): Extracted parallel batch processing pipeline (component collection, glyph batching, atlas rasterization, mesh generation, apply) fromUniText_Parallelinto a shared base partial class. - AddedPer-instance owned sub-meshes: Each effect pass and face segment renders via a dedicated child GameObject (
-_UTWSM_-) with its own MeshFilter + MeshRenderer + per-instance Mesh (HideFlags.HideAndDontSave). Sorting order controls render layering (effects behind face). - AddedPhased mesh upload: Base vertex data (positions, UV0, UV1, UV3, colors, triangles) written once to all SDF sub-meshes; effect passes then overwrite only changed channels (UV2 + vertex shifts). Skips
Mesh.Clear()when vertex count is unchanged between frames. - AddedUniTextWorldEditor (
Editor/UniTextWorldEditor.cs): Custom inspector forUniTextWorldwith sorting order and sorting layer controls. - AddedUniTextBaseEditor (
Editor/UniTextBaseEditor.cs): Extracted shared editor base class fromUniTextEditorfor reuse by bothUniTextEditorandUniTextWorldEditor. - AddedSmallCapsModifier (
Runtime/ModCore/Modifiers/SmallCapsModifier.cs): Renders lowercase letters as small capitals. Two-tier approach: (1) Native — activates OpenTypesmcpfeature via HarfBuzz for proper small cap glyphs; (2) Synthesis — converts to uppercase and scales down by 0.8x (fallback for fonts withoutsmcp). Per-codepoint attribute byte: 0 = unchanged, 1 = native, 2 = synthesis. Synthesis adjusts both vertex positions and shaped glyph advances. - AddedLowercaseModifier (
Runtime/ModCore/Modifiers/LowercaseModifier.cs): Transforms text to lowercase within marked ranges. Applied during modifier Apply phase before shaping. - Added
smcpfeature detection inShaper:HasSmcpFeature()test-shapes'a'with and withoutsmcpfeature, compares glyph IDs. Result cached per font ID insmcpSupportCache. - AddedHarfBuzz feature support:
hb_feature_tstruct andShape(font, buffer, features)overload for passing OpenType features to shaping.MakeTag()utility for constructing OpenType tag values. - AddedShaper features parameter:
Shaper.Shape()now accepts optionalhb_feature_t[]for per-run OpenType feature activation (used by SmallCaps forsmcp). - AddedUI Creation Prefabs on
UniTextSettings:textPrefabandbuttonPrefabfields for customizingGameObject/UI/menu item creation. - AddedFreeType
OutlineDecompose: New native API that decomposes glyph outlines into quadratic Bezier segments in design units, replacing the old SDF bitmap rendering path. - AddedFaceInfo extensions: Added
weightClass(CSS 100-900 from OS/2usWeightClass) andisItalic(from FreeTypestyle_flags) to theFaceInfostruct. - AddedDefaultParameterAttribute (
Runtime/Attributes/DefaultParameterAttribute.cs): Declares default parameter values for modifiers, enabling parameter auto-fill in the editor. - AddedParameterFieldUtility (
Editor/ParameterFieldUtility.cs): Extracted shared parameter field drawing logic fromRangeRuleDataDrawerfor reuse byDefaultParameterDrawerand other editors. - AddedEmoji atlas Texture2DArray:
EmojiFontnow maintains aTexture2DArraysynced from stagingTexture2Dpages, with incremental dirty-page sync. - AddedColorParsing (
Runtime/ModCore/ColorParsing.cs): Shared static utility for parsing hex (#RGB, #RRGGBB, #RRGGBBAA) and 21 named colors. Extracted fromColorModifierfor reuse by OutlineModifier, ShadowModifier, and RangeRuleDataDrawer.
- Changed
UniTextcomponent refactored: shared logic (text processing, modifier management, dirty flags, lifecycle, parallel pipeline) extracted toUniTextBase.UniTextretains only Canvas-specific rendering (CanvasRenderer, stencil,UpdateGeometry). - Changed
UniText_Parallelrefactored: batch pipeline logic extracted toUniTextBase_Parallel.UniText_Parallelretains only Canvas-specific click handling. - ChangedMesh generator callbacks renamed to camelCase:
OnGlyph→onGlyph,OnAfterPage→onAfterPage,OnRebuildStart→onRebuildStart,OnRebuildEnd→onRebuildEnd. - ChangedMesh generator: removed unused public fields (
currentShapedGlyphIndex,x,y,width,xScale,atlasSize,gradientScale,spreadRatio,rectWidth,hAlignment,currentFontId).SetHorizontalAlignment()method removed. - Changed
UniTextFontProvider: renamedMainFont→PrimaryFont,MainFontId→PrinaryFontId. Internal field names updated accordingly. - Changed
EmojiFont: emoji atlas textures now use mipmaps (Texture2DandTexture2DArraycreated withmipmap=true). Filter mode changed toTrilinearwithmipMapBias = -0.5f. Packing spacing increased from 1 to 4 pixels to prevent mipmap bleeding. - ChangedAll modifier base classes updated to use renamed
UniTextBasereferences instead ofUniText. - ChangedMesh generator rewritten from group-by-font-then-atlas iteration to single-pass loop over all positioned glyphs. SDF glyphs look up tiles in the shared
GlyphAtlas; emoji glyphs processed separately inGenerateEmojiSegment. - ChangedUV encoding changed: UV0.zw =
(tileIdx, glyphH)for atlas tile lookup; UV1 =(aspect, faceDilate)asVector2(wasVector4). - ChangedGlyph metrics now use design units directly throughout the pipeline — removed
pointSize-basedmetricsConversionfactor. - Changed
UniTextRenderDatasimplified to carry only mesh and font ID; materials assigned externally viaUniTextMaterialCache. - ChangedMulti-pass effect rendering in
UpdateSubMeshes: effect passes render before the face pass, each with apply/revert callbacks modifying UV2 and vertex positions. - ChangedRequired canvas shader channels extended to include
TexCoord2andTexCoord3for effect layers. - ChangedGlyph reference counting:
UniTextcomponent trackscurrentGlyphKeysand callsAddRef/Releaseon the atlas, enabling accurate eviction. - ChangedAtlas pre-allocation: estimated tile area per atlas mode calculated before rendering, enabling
GlyphAtlas.PreAllocate(). - ChangedPeriodic atlas maintenance: page recycling every 60 frames, atlas shrinking every 300 frames.
- ChangedMesh generator glyph lookup changed from
fontHash(int) tovarHash48(long) — supports variable font axis variation.variationMapfrom buffers used to resolve per-run variation hashes. - Changed
UniTextFontno longer owns atlas textures — all atlas management delegated toGlyphAtlassingletons. - ChangedGlyph preparation/rendering pipeline rewritten:
PrepareGlyphBatchfilters viaGlyphAtlas.TryGetEntryand protects existing entries withAddRef;RenderPreparedBatchextracts curves viaGlyphCurveCache(supports parallel extraction);PackRenderedBatchqueues segments toGlyphAtlas.EnsureGlyph. - Changed
CreateFontAsset()simplified — removedsamplingPointSize,spreadStrength,renderMode,atlasSizeparameters. - Changed
ClearDynamicData()disposes curve cache and clears font entries from the shared atlas instead of destroying per-font textures. - Changed
OnDestroy()now callsShaper.ClearCache()to properly release HarfBuzz native data (was previously leaking). - Changed
FaceInfo.pointSizeremoved; replaced byweightClassandisItalicfields. - ChangedHarfBuzz memory:
Shaper.FontCacheEntrynow pins the managedbyte[]viaGCHandleinstead of copying to unmanaged memory viaMarshal.AllocHGlobal, eliminating the duplicate font data in memory. - ChangedGlyph lookup key changed from
uint glyphIndextolong glyphKey(48-bit variation hash + glyph index) viaGlyphAtlas.MakeKey(varHash48, glyphIndex). Enables the same font to cache different glyph shapes for different variable font axis values. - Changed
PrepareGlyphBatchandRenderPreparedBatchnow acceptvarHash48andftCoordsparameters for variable font rendering. FreeType design coordinates set before glyph extraction. - ChangedRemoved
Appearanceproperty andGetMaterials()method fromUniTextFontProvider. - ChangedConstructor no longer takes an
appearanceparameter. - ChangedConstructor now calls
BuildResolvedFamilies()to flatten the entire fallback chain into aresolvedFamilies[]array withfontIdToFamilyIndexdictionary for O(1) family lookup. - Changed
HasVariants/FindVariant()replaced byHasFacesproperty,GetFamilyIndex(int fontId)andGetFamilyLookup(ushort familyIndex)for direct access toFontFaceLookup. - ChangedFont batch key changed from
UniTextFontreference to(UniTextFont, RenderModee, varHash48)struct — variable font runs with different axis values are batched separately. - ChangedGlyph collection no longer filters already-atlased glyphs at collection time.
- Changed
RasterizeGlyphBatchesextracted as a separate method with per-batch timing diagnostics. - Changed
DoGenerateMeshDatanow clears virtual glyphs buffer, invokesBeforeGenerateMesh, and passes virtual glyphs alongside regular glyphs toGenerateMeshDataOnly. - Changed
PeriodicAtlasMaintenance()extracted as a separate static method, called before component processing instead of after. - Changed
BaseLineModifierrefactored: line segment computation extracted intoComputeLineSegments(), executed once then rendered per page. No longer restricted to matching the current font. Event hook changed fromOnAfterGlyphsPerFonttoOnAfterPage. - Changed
LineRenderHelperrewritten from 3-quad atlas-based rendering (12 vertices) to 1-quad tile-based rendering (4 vertices) usingGlyphAtlas.TryGetEntryfor underscore glyph lookup. - Changed
EllipsisModifierchanged from immediate mesh drawing (GlyphRenderHelper.DrawString) to virtual glyph injection intovirtualPositionedGlyphs. Event hook changed fromOnAfterGlyphsPerFonttoBeforeGenerateMesh. - Changed
ListModifierchanged from immediate mesh drawing to virtual glyph injection, same pattern asEllipsisModifier. Parameter separator changed from:to,. - Changed
LineHeightModifierparameter format changed froms:valuetos,value(comma-separated). - Changed
ColorModifiercolor parsing logic extracted to sharedColorParsingutility class. - Changed
ItalicModifiernow skips vertex shear when the resolved font is already natively italic (FaceInfo.isItalic). - Changed
BoldModifierParameterFieldformat changed from"int"to"int(100,900)"for range-constrained editor UI. - Changed
UniTextFontToolsWindowrenamed toUniTextToolsWindow; menu item changed toTools/UniText Tools. File list refactored into reusableDrawFileList()method. - ChangedFont editor: removed Atlas Settings section (point size, atlas size, spread, render mode). Replaced with Settings section (font scale, SDF detail multiplier). Atlas preview changed from per-font
Texture2Dto sharedTexture2DArrayslices. - ChangedType selector dropdown replaced by
Selectorpopup with icons, descriptions, and group navigation. - ChangedEditor resource path changed from
Icons/{name}toUniText/Icons/{name}. - ChangedSettings provider no longer draws
defaultAppearance; now draws UI Creation Prefabs and Word Segmentation sections. - Changed
EmojiFontmaterial shader changed fromUI/DefaulttoUniText/Emoji(viaUniTextSettings.GetShader). - Changed
SearchableSelectorrenamed toSelector(file and class). AddedshowSearchparameter toShow()for hiding the search field. - ChangedFont editor: added Apply/Revert buttons for rebuild-required properties (
sdfDetailMultiplier,glyphOverrides). Changes are staged as pending until explicitly applied. - Changed
RangeRuleDataDrawer: shared parameter field drawing logic extracted intoParameterFieldUtilityfor reuse.
- RemovedUniTextAppearance (
Runtime/FontCore/UniTextAppearance.cs): Deleted. ScriptableObject that mapped fonts to rendering materials with per-frame property delta caching. Material management replaced byUniTextMaterialCache. - RemovedSDF rendering classes from FreeTypeParallel (
Runtime/FontCore/FreeTypeParallel.cs):SdfRenderedGlyphstruct andSdfGlyphRendererclass removed.FreeTypeFacePoolrewritten — SDF bitmap rendering viaFT.RenderSdfGlyph()removed, class retained for color bitmap/emoji rendering only. SDF generation replaced by curve-basedGlyphCurveCache+ Burst SDF/MSDF jobs. - RemovedGlyphRenderHelper (
Runtime/ModCore/Modifiers/GlyphRenderHelper.cs): Deleted. Immediate glyph mesh generation utility (DrawGlyph,DrawString,MeasureString). Replaced by virtual glyph injection pattern. - RemovedUniTextRenderMode enum (
Runtime/FontCore/FontTypes.cs): Removed (had values: SDF, Smooth, Mono). Replaced byUniText.RenderModeeenum (SDF, MSDF) on the component. - RemovedAtlasMode enum (
Runtime/FontCore/GlyphAtlas.cs): Removed.GlyphAtlas.GetInstance()now takesUniText.RenderModeedirectly. - RemovedPer-font atlas textures:
atlasTextures,atlasSize,spreadStrength,atlasRenderMode,usedGlyphRects,freeGlyphRects, and shelf packing state removed fromUniTextFont. - RemovedFreeType SDF native API:
ut_ft_set_sdf_spread,ut_ft_render_sdf_glyph,ut_ft_free_sdf_bufferP/Invoke declarations and wrappers removed fromFT.cs. - RemovedShader GUIs:
UniText_BitmapShaderGUI.csandUniText_SDFShaderGUI.csdeleted (old custom ShaderGUI for bitmap and SDF shader inspectors). - RemovedIndividual tag parse rule files (14 files):
BoldParseRule.cs,ItalicParseRule.cs,ColorParseRule.cs,SizeParseRule.cs,UnderlineParseRule.cs,StrikethroughParseRule.cs,CSpaceParseRule.cs,LineSpacingParseRule.cs,LineHeightParseRule.cs,GradientParseRule.cs,EllipsisTagRule.cs,ObjParseRule.cs,Link/LinkTagParseRule.cs,UppercaseParseRule.cs. All consolidated intoTagRulewith backward-compatible stubs inDeprecatedTagRules.cs. - RemovedGeneratedMeshSegment struct: Removed from
UniTextMeshGenerator. Replaced byEffectPassstruct for multi-pass rendering. - Removed
defaultAppearancefromUniTextSettingsand its backup system. - Removed
GlyphsByFontgrouping fromSharedPipelineComponents(no longer needed with single-pass mesh generation). - Removed
sourceFontFilePathfromUniTextFont. - Removed
fontsandvariantsfromUniTextFontStack: FlatStyledList<UniTextFont>fonts list andUniTextFont[]variants array replaced byFontFamily[]families. - Removed
FindClosestVariant()fromUniTextFontStack: Replaced byFontFaceLookup.FindFace()with CSS §5.2 directional weight matching. - Removed
CurrentAtlasModeproperty fromUniText: Removed.GlyphAtlas.GetInstance()now takesRenderModedirectly. - RemovedZstd-compressed font data: Font bytes stored in
UniTextFontassets are now compressed with Zstandard (level 22) at import time. Decompression is lazy (on firstFontDataaccess) with zero per-frame cost. Benchmarks: ~600 MB/s on desktop, ~175 MB/s on low-end Android. Typical Latin font (600 KB) decompresses in <1 ms. Build size reduction: ~2.7x for Latin/Arabic fonts, ~1.3x for CJK fonts. - RemovedZstd native integration: Decompression (
ut_zstd_decompress,ut_zstd_get_frame_content_size) built into the runtimeunitext_nativelibrary across all platforms (Windows, Linux, macOS, Android, iOS, tvOS, WebGL). Runtime library built with-DZSTD_BUILD_COMPRESSION=OFFfor minimal size (~80 KB). - RemovedEditor-only compression:
ut_zstd_compressandut_zstd_compress_boundlive inunitext_native_editor(desktop only).Zstd.Compress()is available only under#if UNITY_EDITOR. - RemovedAutomatic migration:
OnValidatedetects uncompressed font data via Zstd magic bytes (0x28B52FFD) and compresses in-place. No manual migration step needed. - RemovedMemory optimization: In runtime builds, compressed
fontDatais freed after decompression to avoid keeping both copies in memory. - RemovedBurst dependency: Added
com.unity.burst>= 1.6.0 to package dependencies.
- FixedHarfBuzz memory leak on font destroy:
UniTextFont.OnDestroy()now callsShaper.ClearCache()to release HarfBuzz native data (unmanaged font copy, hb_blob, hb_face, hb_font). Previously, these resources leaked in the staticfontCacheuntil domain reload. - FixedDuplicate font data in memory: HarfBuzz
FontCacheEntrynow pins the managedbyte[]viaGCHandleinstead of allocating a separate unmanaged copy, halving per-font memory overhead. - FixedFontSize minimum too restrictive:
fontSize,minFontSize,maxFontSizesetters clamped to1fminimum, preventing small text in world-space. Changed minimum to0.01f. - FixedUniTextSettings resilience: Fixed settings loss on package reinstallation.
- FixedUnity 2021/2022 compatibility: Fixed compiler errors for older Unity versions.
