Typewriter Effects (2023)

Make enhanced text for Prompts, Dialogues, and Conversations with this effect.

by Mark_GoodMan

Author Avatar

DIFFICULTY: EASY

Hello you absolute legends, my name is Mark_GoodMan and welcome to the Typewriter Effects tutorial, we are going to see what we can do to achieve this simple yet effective feature.


Explaining

What is a Typewriter effect?

In other words, it's an effect that causes text on GUI to appear over a given period, instead of instantly appearing like most old games do. Here's an example:

SomeTextLabel.Text = "Hey look, it's me!"

This code will make the selected TextLabel instantly change it's current text to the said text. However, most people want to make it more immersive or make some special effects to make it look professional, or at least not making it look low-quality in some cases. This is where the Typewriter effect comes in.


1. Setup

First up, we are gonna insert a ScreenGui into StarterGui, and then insert a TextLabel in it. (For those who don't know, you could click on the ScreenGui and click the plus button "+" to add it)

img|250x45,90%

Customize anything with the TextLabel! Use the properties to adjust how you want your TextLabel to look like, but try to resize it to fit the screen, we don't want people to zoom their eyes in if the text is too small.

img|50x75,75%

Make sure TextScaled is checked, though it is optional, checking this option will automatically scale the size of the text based on a person's device resolution.

Place a Localscript inside the TextLabel, then check to make sure the setup is correct as shown below:

img|90x45,90%

Everything looks good? Great, let's begin the next phase.


2. Scripting

Begin by double-clicking on the LocalScript you inserted.

First thing first, we need to make variable for the current TextLabel.

local AnyTextName = script.Parent

Now after this, there are 2 methods to create a Typewriter effect, however, I recommend the newest method from 2023 as it's more efficient, but the old method will be kept because that's what this tutorial was originally meant to be.


#2.5: METHOD A (2020)


Now, after assigning the variable, we want to make a function, you can call the function anything you want, but I will call it AutoText for an easier understanding. We will add two assignments, object and text, they can be renamed. Make sure to end the function with an end.

local AnyTextName = script.Parent

local function AutoText(object,text)


end

Then we will use for loops to repeat checking each letter. (NOTE: the #text has to be the same as the one you named on the local function)

 for i = 1,#text,1 do

The number 1 after the #text are how many letters you want to type, for example, if you put to 3, then it will type 3 letters every second depending on your task.wait(), but you rarely want that to happen to your dialogue system unless you just want to mess around, so I will leave it at number 1.

Next we want to use string.sub so it will type each letter out as listened to the numbers, the number 1 determines the start of the typing, changing this will cut some letters at the start and you can say it skipped those letters to the letters after it depends on the number, I suggest leaving it at number 1. We will want to use this on any TextLabel that the script is parented to, that's why we put it as object so you don't need to rename the name for any TextLabel with different name.

local function AutoText(object,text)
    for i = 1,#text,1 do
        object.Text = string.sub(text,1,i)
        task.wait(0.05) -- Going below 0.05 can cause issues
    end
end

Having task.wait() will effect how fast the function will type each letter 1 by 1. Then we end the "for do" statement with an end.

Now you understand how the script works, here is the full script:

local AnyTextName = script.Parent

local function AutoText(object,text)
    for i = 1,#text,1 do
        object.Text = string.sub(text,1,i)
        task.wait(0.05) -- Going below 0.05 can cause issues
    end
end

Congratulation, you learned how to make the Typewriter effect! We will move on to method B.


#2.5: METHOD B (2023)


After assigning the variable, now, we begin by making a function that can be made to allow you to do multiple Typewriter effect without copy and pasting on your script. You will need three assignments, which is object, theText, and speed, these values are self-explanatory. However, we also need to use TweenService to make it smooth!

local AnyTextName = script.Parent
local Tween = game:GetService("TweenService")

local function AutoText(object, theText, speed)
         
end

First, we need to put the text we want into our TextLabel as usual, it should be placed in the theText argument (first argument in this local function)

local function AutoText(object, theText, speed)
    object.Text = theText
end

Now, recently Roblox introduced a new property called MaxVisibleGraphemes. It's a property to render a specific amount of text string with the given number value (think of it like making the whole text invisible when the value sets to 0, but as the number increases, more characters will become visible), with this in mind, we can use it intentionally as a Typewriter effect!

That being said, the next thing we should do is create a tween for our new text when we enter them soon. Combine the TextLabel variable, with the Tween information variable, and then the Text we want to give in the table to animate it! Don't forget to set the value of MaxVisibleGraphemes at 0 at the start each time this function fires.

One more thing, the MaxVisibleGraphemes will automatically be determined based on how many characters you wrote at theText, so you don't have to do it manually (Which is #theText, used to calculate the total amount of characters the given text has).

local function AutoText(object, theText, speed)
    object.MaxVisibleGraphemes = 0 -- Pretend the text got deleted
    object.Text = theText
    Tween:Create(object, TweenInfo.new(speed), {MaxVisibleGraphemes = #theText}):Play()
end

Alright, it seems like everything is working, here's the full code to double-check:

local AnyTextName = script.Parent
local Tween = game:GetService("TweenService")

local function AutoText(object, theText, speed)
    object.MaxVisibleGraphemes = 0 -- Pretend the text got deleted
    object.Text = theText
    Tween:Create(object, TweenInfo.new(speed), {MaxVisibleGraphemes = #theText}):Play()
end

3. Test the Typewriter effect

Let's test out the code to confirm that it works!

Again, this will split into neither of both METHOD A and B:

#METHOD A

As previously mentioned, the object is the TextLabel your going to target, and the text is the text you want that given target to write out.

local AnyTextName = script.Parent

local function AutoText(object,text)
    for i = 1,#text,1 do
        object.Text = string.sub(text,1,i)
        task.wait(0.05) -- Going below 0.05 can cause issues
    end
end

task.wait(5) -- Load the game first or the text will finish before your eyes
AutoText(AnyTextName, "i dont know what to put here lol")

After this, you can run the game to test the code.

Now I tested it myself, and it worked, but let's see how it actually looks like. Also, make sure the GUI size fits the screen, put it on top so you can easily see it and spot the text changing.

img|100x45,90%

img|100x45,90%

img|100x45,90%

Wow, that was an awesome magic trick right there buddy! It took ~1.43 seconds to complete animating the text "i dont know what to put here lol". Very well indeed! It looks like everything is done, congratulation!

#METHOD B

This new method has the same results as METHOD A. However, this one will animate the text more smoothly, while the text will stay in its position and doesn't move when new texts are rendered. It's also not dependent on your FPS, unlike method A.

Why don't you go try it yourself?

local AnyTextName = script.Parent
local Tween = game:GetService("TweenService")

local function AutoText(object, theText, speed)
    object.MaxVisibleGraphemes = 0 -- Pretend the text got deleted
    object.Text = theText
    Tween:Create(object, TweenInfo.new(speed), {MaxVisibleGraphemes = #theText}):Play()
end

-- Setting "speed" to 2.5 means it takes 2.5 seconds to animate the text
while task.wait(4) do
    AutoText(AnyTextName, "uhh, what am i doing here?", 2.5)
    task.wait(4)
    AutoText(AnyTextName, "it seems like its raining a lot here man", 2.5)
end

img|100x100,90%

img|100x100,90%

Now one final thing to note is that the method B that I wrote wasn't as efficient, you could use something such as the utf8 library to make a better version of Typewriter than mine, but I'm only here to show the basics.


#4. ENDING & EXTRAS:

I would like to thank you everyone for reaching the end, and for reading this tutorial.

I hope this serves you when you're making your own game, goodluck and have fun!

#Both method are included, copy the ones that you need.

RANDOMIZED TYPEWRITER (Select a random text in the given table then animate it)

local RandomTextTable = {
"Hey, a random text I guess?",
"Can I have another one please? Thanks.",
"Yo, this is getting so random, uh...",
"The heck is this abomination dude?",
"Hey man, have you ever wonder why we are having randomized texts?",
"I am your best friend here to save you from hours of coding!!!",
"Final text and goodbye lol",
-- If you want to put more text, make sure to put a comma after the text ( , )
}

-- METHOD A (2020)
while task.wait(5) do
    AutoText(AnyTextName, RandomTextTable[math.random(1,#RandomTextTable)])
end

-- METHOD B (2023)
while task.wait(5) do
    AutoText(AnyTextName, RandomTextTable[math.random(1,#RandomTextTable)], 3)
end

SOUNDS ON TYPEWRITER (Plays a specific sound when animating the text)

-- This modified function plays a sound for each letter animated
-- ONLY USE SHORT SOUNDS THAT TYPICALLY LAST FOR <1 SECOND
-- METHOD A (2020)
local function AutoText(object,text,soundToPlay)
    for i = 1,#text,1 do
        object.Text = string.sub(text,1,i)
        soundToPlay:Play() -- Play the selected sound
        task.wait(0.05) -- Going below 0.05 can cause issues
    end
end

AutoText(AnyTextName, "very noisy typewriter, dude...", --[[The sound to play]])


-- This modified function only plays a single but long sound when AutoText was called
-- If the sound duration is shorter than the "speed" of the AutoText, then check the Looped on
-- METHOD B (2023)
local function AutoText(object, theText, speed, soundToPlay)
    object.MaxVisibleGraphemes = 0 -- Pretend the text got deleted lol
    object.Text = theText
    local Animate = Tween:Create(object, TweenInfo.new(speed), {MaxVisibleGraphemes = #theText})
    Animate:Play()
    local DupedSound = soundToPlay:Clone() -- Clone the sound
    DupedSound.Parent = script
    DupedSound:Play()
    Animate.Completed:Connect(function() -- Also runs when the tween got cancelled
        DupedSound:Stop() -- If completed, then we will stop the sound
    end)
    -- This will make sure the sound doesn't conflict with another when multiple AutoText was called
end

AutoText(AnyTextName, "yea so I heard that something is coming...", 3, --[[The sound to play]])

View in-game to comment, award, and more!