Ok sure, here’s something pretty hastily made but from my testing it works. It has 2 options: first one is calculated automatically based on textLabel.TextBounds (needs textLabel.TextScaled enabled initially), second one is calculated manually. It does have a very slight size discrepancy depending on if you have a character below the base line (ie the lowercase letters g, q, p, y), but I’m not sure there’s much that can be done about that.
local textService = game:GetService('TextService')
local textSizeParams = Instance.new('GetTextBoundsParams')
local containerManual = script.Parent.Manual
local containerAuto = script.Parent.Auto
local function getSmallestSizeFactor() -- case of wanting to compute from the automatically calculated TextBounds
-- get the maximum size factor of text that can fit in the label for all labels
local minYFactor
for _, container in containerAuto:GetChildren() do
if not container:IsA('TextLabel') then
continue
end
local isDoneCalculatingTextBounds = container.TextBounds ~= Vector2.zero
if not isDoneCalculatingTextBounds then
container:GetPropertyChangedSignal('TextBounds'):Wait()
end
local yAxisFactor = container.TextBounds.Y / container.AbsoluteSize.Y -- should give us a float between 0 and 1 which is the % height of the text in the label
if not minYFactor or yAxisFactor < minYFactor then
minYFactor = yAxisFactor
end
end
return minYFactor
end
local function getSmallestSizeFactorManual() -- case of wanting to find the size manually
local minYFactor
for key, child in containerManual:GetChildren() do
if not child:IsA('TextLabel') then
continue
end
textSizeParams.Width = 0 -- 0 for no wrapping
textSizeParams.Font = child.FontFace
textSizeParams.Size = child.AbsoluteSize.Y
textSizeParams.Text = child.Text
local textBounds = textService:GetTextBoundsAsync(textSizeParams)
local aspectRatio = textBounds.X / textBounds.Y
-- now we have to scale it down to fit within textLabel.AbsoluteSize.X
local requiredSize = child.AbsoluteSize.X / textBounds.X
-- now we can multiply textBounds by requiredSize and it /should/ give us a new text bounds that fits within `child`'s bounds
local multipliedTextBounds = textBounds * requiredSize
-- now for the Y factor
local yAxisFactor = multipliedTextBounds.Y / child.AbsoluteSize.Y
if not minYFactor or yAxisFactor < minYFactor then
minYFactor = yAxisFactor
end
end
return minYFactor
end
-- USAGE:
local yFactor = getSmallestSizeFactorManual()
for _, child in containerManual:GetChildren() do
if not child:IsA('TextLabel') then
continue
end
local function handleChildChanged()
child.TextSize = math.floor(yFactor * child.AbsoluteSize.Y) - 1 -- subtract 1 as safeguard. sometimes the last letter will get cut off by 1 pixel
end
child.TextScaled = false
child:GetPropertyChangedSignal('AbsoluteSize'):Connect(handleChildChanged)
handleChildChanged()
end
-- (auto)
local yFactor = getSmallestSizeFactor()
for _, child in containerAuto:GetChildren() do
if not child:IsA('TextLabel') then
continue
end
local function handleChildChanged()
child.TextSize = math.floor(yFactor * child.AbsoluteSize.Y) - 1 -- subtract 1 as safeguard. sometimes the last letter will get cut off by 1 pixel
end
child.TextScaled = false
child:GetPropertyChangedSignal('AbsoluteSize'):Connect(handleChildChanged)
handleChildChanged()
end