Text+|Custom fonts & fine-control

Text+ logo

A lightweight, open-source text rendering module for Roblox,
featuring custom fonts and fine-control over all characters.

Module button Github button



:art: More creativity!

Roblox developers suffer from a wide range of limitations.

This module aims to fix text limitations, allowing more
developers to unleash their creativity with text.

What it really does:

  • Custom fonts: You can use .ttf and .otf files, either custom fonts or fonts you find online.
  • Fine-control: Transform and style any individual character, word or line. Useful for dialogues.

:eyes: Check it out below!

🎬 Showcases

Dialogue

A really simple ‘dialogue’, featuring:

  • Custom font.
  • Text appear and disappear animation.
  • ‘Shining’ word animation.

Text explosion

A neat text explosion effect. :exploding_head:
Features a custom font too.

:zap: Efficient, typed, robust.

  • It’s blazingly fast.
  • It has types for all functions & arguments.
  • It catches nearly all mistakes, providing detailed error messages.

And it’s light as a feather! :feather:

:bulb: Learn how to use it!

🚀 Fundamentals

Getting the module

Let’s first get the module. There are two ways:

  • Get it from the creator store:
    • Click Get at the top of this post.
    • Click Get Model on the store.
    • Open the ToolBox in Roblox Studio.
    • Go to the Inventory tab.
    • Click on Text+.
  • Get it from GitHub:
    • Click Git at the top of this post.
    • Go to Releases.
    • Download the latest .rbxm file.
    • Find the file in your file explorer.
    • Drag the file into Roblox Studio.

Find a great place for the module in your explorer.

Introduction

You’ll be creating text using frames as parents and boundaries, like this:

local textPlus = require(path.to.TextPlus) -- Put the actual path to the module.

local frame = path.to.frame -- You should actually get or create a frame.

textPlus.Create(
	frame, -- Parent and boundary.
	"This text is awesome!", -- Text.
	{ -- Customization (optional).
		Size = 24,
		Color = Color3.fromRGB(255, 255, 255),
		XAlignment = Enum.TextXAlignment.Center,
		YAlignment = Enum.TextYAlignment.Center,
	}
)

The text will be wrapped inside of the frame.
Note that it will ignore any UIPadding.

Customization

The customization works with a table, where you can provide any customizations you want.
You don’t have to provide all, or even any, because they all have defaults.

Full list of customization options:

  • Size: number
  • Font: Font
  • Color: Color3
  • Transparency: number
  • LineHeight: number
  • CharacterSpacing: number
  • XAlignment: Enum.TextXAlignment
  • YAlignment: Enum.TextYAlignment
  • WordSorting: boolean
  • LineSorting: boolean

Fonts

The font is one of the customization options, and generally works like all the others.
It’s slightly different though.
It uses a Font object, usually created with Font.new().

You can use it like this:

textPlus.Create(
	frame,
	"This text is awesome!",
	{
		Font = Font.new(
			"rbxasset://fonts/families/Arial.json", -- Family.
			Enum.FontWeight.Regular, -- Weight.
			Enum.FontStyle.Normal -- Style.
		)
	}
)

Built-in fonts

You can find a lot of fonts on the documentation page.

Simply copy the asset id from the font list and paste it into the Font object’s Family (first argument).

Creator store fonts

Alternatively, browse many more fonts at the creator store.

Click Get Font.

Create a TextLabel in Roblox Studio and apply the font to it.

Make sure you have the TextLabel selected and run this in the command bar:

print(game.Selection:Get()[1].FontFace.Family)

It will output the asset id, that you need.
Simply copy and paste it into the Font object’s Family (first argument).

Custom fonts

If it’s still not enough, custom fonts offer endless possibilities.
But that has it’s own section (also in this post). Consider checking it out.

Modification

You can also modify a text frame after the creation. It’s done the same you create it to begin with:

textPlus.Create(
	frame, -- Frame that already has text created within it.
	"This text has been modified!" -- New text.
)

You can even modify the customization after the creation like this:

textPlus.Create(
	frame, -- Frame that already has text created within it.
	"This text has been modified!", -- New text.
	{ -- New customization (optional).
		Size = 12 -- Overwrite size.
		-- Everything else will stay like before!
	}
)

It will keep all previous customization options, only overwriting with those you provide in the table.

⚙️ Fine-control

Introduction

The sorting options in the customization are crucial to fine-control.
Using word and line sorting, you can not only modify individual characters, but whole words and lines.

Use the sorting customization options like this:

textPlus.Create(
	"Text",
	frame,
	{
		LineSorting = true,
		WordSorting = true
	}
)

Both lines and words will be sorted using folders, and will be named numerically:

image

Full looping

If you want to loop through them in correct order, you will have to use numerical loops like this:

for lineNumber = 1, #frame:GetChildren(), 1 do
	print("Line "..lineNumber) -- "Line 1", "Line 2" etc.
	
	local lineFolder = frame[tostring(lineNumber)]
	for wordNumber = 1, #lineFolder:GetChildren(), 1 do
		print("Word "..wordNumber) -- "Word 1", "Word 2" etc.
		
		local wordFolder = lineFolder[tostring(wordNumber)]
		for characterNumber = 1, #wordFolder:GetChildren(), 1 do
			print("Character "..characterNumber) -- "Character 1", "Character 2" etc.
			
			local character = wordFolder[tostring(characterNumber)]
			-- For Roblox fonts, 'character' will be a TextLabel.
			-- For custom fonts, 'character' will be an ImageLabel.
		end
	end
end

Of course, if you have only one of the sorting types enabled, there will only be one layer of folders, and you’ll have to do something like this:

for wordNumber = 1, #frame:GetChildren(), 1 do
	print("Word "..wordNumber) -- "Word 1", "Word 2" etc.
	
	local wordFolder = frame[tostring(wordNumber)]
	for characterNumber = 1, #wordFolder:GetChildren(), 1 do
		print("Character "..characterNumber) -- "Character 1", "Character 2" etc.
		
		local character = wordFolder[tostring(characterNumber)]
		-- For Roblox fonts, 'character' will be a TextLabel.
		-- For custom fonts, 'character' will be an ImageLabel.
	end
end

Alternatively, you can use the GetCharacters function, which will return all of the characters.
You can simply loop through the table like this:

local characters = textPlus.GetCharacters(frame)
for _, character in ipairs(characters) do
	-- For Roblox fonts, 'character' will be a TextLabel.
	-- For custom fonts, 'character' will be an ImageLabel.
end

Specific indexing and looping

You can always access the exact line, word or character number you want by indexing like this:

frame["1"]

With some sorting enabled, you’ll be able to loop through specific lines and words.

Character (requires you to have no sorting)

for _, character in ipairs(frame:GetChildren()) do
	-- For Roblox fonts, 'character' will be a TextLabel.
	-- For custom fonts, 'character' will be an ImageLabel.
end

Word (requires word sorting)

local word = frame["1"] -- Word sorting.
local word = frame["1"]["1"] -- Line and word sorting.
for _, character in ipairs(word:GetChildren()) do
	-- For Roblox fonts, 'character' will be a TextLabel.
	-- For custom fonts, 'character' will be an ImageLabel.
end

Line (requires line sorting)

local line = frame["1"]

-- Line and word sorting:
for _, word in ipairs(word:GetChildren()) do
	-- 'word' will be a folder.
	for _, character in ipairs(word:GetChildren()) do
		-- For Roblox fonts, 'character' will be a TextLabel.
		-- For custom fonts, 'character' will be an ImageLabel.
	end
end

-- Line sorting:
for _, character in ipairs(line:GetChildren()) do
	-- For Roblox fonts, 'character' will be a TextLabel.
	-- For custom fonts, 'character' will be an ImageLabel.
end

Transform and style

If you want to change the colors of characters, remember that:

  • For Roblox fonts: Use TextColor3, because it will be a TextLabel.
  • For custom fonts: Use ImageColor3, because it will be an ImageLabel.

If you want to change the transparency of characters, remember that:

  • For Roblox fonts: Use TextTransparency, because it will be a TextLabel.
  • For custom fonts: Use ImageTransparency, because it will be an ImageLabel.

And don’t forget to be creative!

🛠️ Custom fonts

Importing custom fonts is slightly complex. Bear with me. :bear:

Get and open BMFont app

Download and install the latest version of AngelCode’s BMFont app.
Unzip/extract the .zip file.

Open the bmfont64.exe file that is inside of the bmfont folder.
A window should pop up.

Include characters

Tick the box next to Latin on the right side:

It will now include the latin alphabet.
You can include more characters if you want, but this is usually all we need.

Install your font

Get a .ttf or .otf file (a font file), whether it’s one of your own or one you found online.
Open it and press Install, or simply right-click and press Install.

Font settings

In the BMFont app, go to Options > Font settings, or simply press F on your keyboard.

Find your font in the Font dropdown located at the top, and select it.

You might want to adjust the Size option.
This basically controls the maximum size you will be able to render this font in before it begins to look awful (due to low quality). Now you might think that you should just set this to a huge number like 1.000, but you’ve got to remember that it’s going to save this as an image. If you’re not going to make the text really large, don’t make this number large. I’d recommend not going further than 100.

Press OK once done.

Export options

In the BMFont app, go to Options > Export options, or simply press T on your keyboard.

Make sure that the Width and Height is large enough to fit all of your characters — it highly depends on the size you put in the font settings.

Set Bit depth to 32.

Find the Presets dropdown, located near the bottom, and choose White text with alpha. Don’t worry, it will still be colorable!

For Font descriptor, choose XML.

For Textures, choose png.

Press OK once done.

Save the image and XML font files

In the BMFont app, go to Options > Save bitmap font as..., or simply press CTRL+S on your keyboard.
Choose a location where you’ll be able to find the files.

It should save a .fnt and a .png file.

Convert XML to Lua format

I’ve made this step nice and simple with a program that does this for you.

Download the converter.
Unzip/extract the zip file.
You should get a folder with a convert.exe file inside.

Drag your .fnt file, that you exported from the BMFont app, into the folder where the converter.exe file is.

Then simply open the convert.exe file.
It might warn you, saying it might be a threat (virus). This is simply because I haven’t registered the file, as it’s extremely expensive to do so.

After a few short seconds, you should see a new .lua file.

Uploading image and getting its id

Upload the image at the creator hub.

Then go to your images.
Find your image, click the three dots on it, and then click Copy Asset ID.

Import font data to Text+

Find the TextPlus module in your explorer.
Open the CustomFonts module located inside of it.

Custom fonts work like this:

return table.freeze({
	-- Fonts.
	MyFont = {
		-- Weights.
		Regular = {
			-- Styles.
			Normal = {
				Image = 0, -- Image id.
				-- From XML:
				Size = 32,
				Characters = {
					
				}
			}
		}
	}
})

Each font can have multiple weights that all can have multiple styles.
One weight is required per font.
One style is required per weight.

All possible font weights (in ascending order):

  • Thin
  • ExtraLight
  • Light
  • Regular
  • Medium
  • SemiBold
  • Bold
  • ExtraBold
  • Heavy

Add your font like this:

MyFont = {
	Regular = {
		Normal = -- Paste lua file content here.
	}
}

If you’re using a different weight or style, change the Regular and Normal.
You can always add more weights and styles by repeating the custom font creation process and adding the data here.

Add your image id of the font in the same table as the Size and Characters like this:

MyFont = {
	Regular = {
		Normal = {
			Image = 0, -- Image id.
			Size = 32,
			Characters = {
				
			}
		}
	}
}

Use the custom font

Using custom fonts is as simple as using any Roblox font.

Just set the Font customization’s Family (first argument) to the exact name you gave the font in the CustomFonts module. Like this:

textPlus.Create(
	"Text",
	frame,
	{
		Font = Font.new(
			"MyFont",
			Enum.FontWeight.Regular,
			Enum.FontStyle.Normal
		)
	}
)

:loudspeaker: Share your thoughts and creations!

I’d love to see what you guys are able to do with this, so consider sharing your works!

But most importantly:

  • Report any bugs or mistakes you find for this asset and post!
  • Consider providing feedback to help me and the asset improve!
30 Likes

im nooticing :face_with_monocle:


7 Likes

It’s the previous version of this module, posted by my alt account.
I’ll get rid of the old post.

4 Likes

Oh no, it’s fine if so, it was just unsure if it was your alt or not. Instead of completely deleting it, you should edit the original post and link this post at the very top.

4 Likes

Hell yeah! Dude that’s amazing. Have been looking to something like this for a while.

2 Likes

this seems pretty, cool im bookmarking this fs!

1 Like

This is really cool!
Im not joking im already trying to implement this into my game lol

1 Like

how are animations applied for this module?

1 Like

Looks nice! Would text localization still works using this module?

1 Like

based on what ive seen the power of the module comes in that every character of the string is split into its own text label. You can use one of the functions to get all the characters in the text and then loop through them to do effects on them. at least thats what ive been doing. (let me know if this isnt what your supposed to be doing)

2 Likes

You should make an example place for these to show how the module should be used.

3 Likes

Unfortunately automatic text localization won’t detect text created using Text+.

Sounds like a great idea!

Do note that there’s already a detailed guide on how you use the module, so don’t skip that!

2 Likes