Hello,
I’m currently experimenting around with animating each individual letter of a text. Each letter is it’s own TextLabel within a Frame and I position them side by side based on their TextBounds.
However when testing on different devices the alignment slightly breaks even though I’m updating positions whenever the container’s AbsoluteSize changes.
How can I ensure the letters stay perfectly aligned and maintain consistent spacing, regardless of the screen size or resolution?
Code for individual TextLabel
--[=[
@class TitleScreenLoadingEntry
]=]
local require = require(script.Parent.loader).load(script)
local TextService = game:GetService("TextService")
local BasicPane = require("BasicPane")
local Blend = require("Blend")
local ValueObject = require("ValueObject")
local Rx = require("Rx")
local TitleScreenLoadingEntry = setmetatable({}, BasicPane)
TitleScreenLoadingEntry.ClassName = "TitleScreenLoadingEntry"
TitleScreenLoadingEntry.__index = TitleScreenLoadingEntry
function TitleScreenLoadingEntry.new()
local self = setmetatable(BasicPane.new(), TitleScreenLoadingEntry)
self._percentVisibleTarget = self._maid:Add(ValueObject.new(0))
self._labelText = self._maid:Add(ValueObject.new(""))
self._textSize = self._maid:Add(ValueObject.new(0))
self._entryHeight = self._maid:Add(ValueObject.new(0))
self._maid:GiveTask(self.VisibleChanged:Connect(function(isVisible)
self._percentVisibleTarget.Value = isVisible and 1 or 0
end))
return self
end
function TitleScreenLoadingEntry:SetText(text: string)
self._labelText.Value = text
self:_adjustBounds()
end
function TitleScreenLoadingEntry:_adjustBounds()
local bounds = TextService:GetTextSize(
self._labelText.Value,
self._entryHeight.Value * 0.8,
Enum.Font.ArimoBold,
Vector2.new(math.huge, math.huge)
)
self._textSize.Value = bounds.X
end
function TitleScreenLoadingEntry:Render(props)
local target = self._percentVisibleTarget:Observe()
local percentVisible = Blend.Spring(target, 25, 0.6)
local percentAlpha = Blend.AccelTween(target, target:Pipe({
Rx.map(function(value)
return value == 1 and 200 or 400
end)
}))
local transparency = Blend.Computed(percentAlpha, function(percent)
return 1 - percent
end)
local rotation = Blend.Computed(percentVisible, function(percent)
return 45 - percent * 45
end)
return Blend.New "Frame" {
Name = "LoadingEntry";
BackgroundTransparency = 1;
Parent = props.TargetParent;
Size = Blend.Computed(self._textSize, function(size)
return UDim2.new(0, size, 1, 0)
end);
[Blend.OnChange "AbsoluteSize"] = function(size)
self._entryHeight.Value = size.Y
self:_adjustBounds()
end;
Blend.New "TextLabel" {
Name = "label";
AnchorPoint = Vector2.new(0.5, 0.5);
BackgroundTransparency = 1;
Rotation = rotation;
TextTransparency = transparency;
TextColor3 = Color3.fromRGB(231, 227, 209);
FontFace = Font.fromEnum(Enum.Font.ArimoBold);
Size = UDim2.fromScale(1, 1);
Position = Blend.Computed(percentVisible, function(percent)
return UDim2.fromScale(-0.5 + percent, 1.5 + -percent)
end);
TextSize = Blend.Computed(self._entryHeight, function(size)
return size * 0.8
end);
Text = Blend.Computed(self._labelText, function(text)
return text
end)
}
}
end
return TitleScreenLoadingEntry
Here’s a short clip of my problem: