Is it possible to use shotstack to create typewriter effect such as this?
Potentially something like this:
{
"output": {
"format": "mp4",
"size": {
"width": 500,
"height": 500
}
},
"timeline": {
"soundtrack": {
"src": "https://shotstack-content.s3.amazonaws.com/rocky.mp3",
"effect": "fadeInFadeOut"
},
"fonts": [
{
"src": "https://templates.shotstack.io/basic/asset/font/notosans-bold.ttf"
}
],
"background": "#000000",
"tracks": [
{
"clips": [
{
"asset": {
"height": 30,
"width": 450,
"type": "html",
"html": "<div>The world ain't all sunshine and rainbows.</div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #FFF; font-size: 18px; }"
},
"start": 0,
"length": 5,
"position": "top",
"offset": {
"y": -0.03
}
}
]
},
{
"clips": [
{
"asset": {
"height": 30,
"width": 450,
"type": "html",
"html": "<div>Rocky Balboa</div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #FFF; font-size: 22px; }"
},
"start": 0,
"length": 5,
"position": "top",
"offset": {
"y": -0.09
}
}
]
},
{
"clips": [
{
"start": 3.72,
"length": 1.28,
"position": "center",
"asset": {
"height": 350,
"width": 450,
"html": "<div><span>Let me tell you something you already know</span></div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #dfe4ea; font-size: 55px; } span {color: #FFF;}",
"type": "html"
},
"offset": {
"y": -0.1
}
}
]
},
{
"clips": [
{
"start": 3.44,
"length": 1.56,
"position": "center",
"asset": {
"height": 350,
"width": 450,
"html": "<div><span>Let me tell you something you already</span> know</div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #dfe4ea; font-size: 55px; } span {color: #FFF;}",
"type": "html"
},
"offset": {
"y": -0.1
}
}
]
},
{
"clips": [
{
"start": 3.34,
"length": 1.66,
"position": "center",
"asset": {
"height": 350,
"width": 450,
"html": "<div><span>Let me tell you something you</span> already know</div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #dfe4ea; font-size: 55px; } span {color: #FFF;}",
"type": "html"
},
"offset": {
"y": -0.1
}
}
]
},
{
"clips": [
{
"start": 2.97,
"length": 2.03,
"position": "center",
"asset": {
"height": 350,
"width": 450,
"html": "<div><span>Let me tell you something</span> you already know</div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #dfe4ea; font-size: 55px; } span {color: #FFF;}",
"type": "html"
},
"offset": {
"y": -0.1
}
}
]
},
{
"clips": [
{
"start": 2.86,
"length": 2.14,
"position": "center",
"asset": {
"height": 350,
"width": 450,
"html": "<div><span>Let me tell you</span> something you already know</div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #dfe4ea; font-size: 55px; } span {color: #FFF;}",
"type": "html"
},
"offset": {
"y": -0.1
}
}
]
},
{
"clips": [
{
"start": 2.67,
"length": 2.33,
"position": "center",
"asset": {
"height": 350,
"width": 450,
"html": "<div><span>Let me tell</span> you something you already know</div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #dfe4ea; font-size: 55px; } span {color: #FFF;}",
"type": "html"
},
"offset": {
"y": -0.1
}
}
]
},
{
"clips": [
{
"start": 2.59,
"length": 2.41,
"position": "center",
"asset": {
"height": 350,
"width": 450,
"html": "<div><span>Let me</span> tell you something you already know</div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #dfe4ea; font-size: 55px; } span {color: #FFF;}",
"type": "html"
},
"offset": {
"y": -0.1
}
}
]
},
{
"clips": [
{
"start": 2.44,
"length": 2.56,
"position": "center",
"asset": {
"height": 350,
"width": 450,
"html": "<div><span>Let</span> me tell you something you already know</div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #dfe4ea; font-size: 55px; } span {color: #FFF;}",
"type": "html"
},
"offset": {
"y": -0.1
}
}
]
},
{
"clips": [
{
"start": 1.5,
"length": 3.5,
"position": "center",
"asset": {
"height": 350,
"width": 450,
"html": "<div>Let me tell you something you already know</div>",
"css": "div { line-height: 125%; font-family: \"Noto Sans\"; font-weight: 600; text-align: left; color: #dfe4ea; font-size: 55px; } span {color: #FFF;}",
"type": "html"
},
"offset": {
"y": -0.1
},
"transition": {
"in": "fadeFast"
}
}
]
},
{
"clips": [
{
"start": 0,
"length": 5,
"asset": {
"type": "image",
"src": "https://media.discordapp.net/attachments/915787846063915052/920466103535284224/rocky.png"
}
}
]
}
]
}
}
Ok, I see what you are doing! Let me play with it. Thank you!
hey! super interested in this too. I think I got it more or less:
- shorten time of each clip so it does one word by one word
The problem if I understand this correctly is that it is not scalable with various dynamic text.
Would there be any other approach? Have you implemented any other effect to animate text @dazzatron ?
This would be amazing feature for engagement on the videos rather than have a full text directly showing…
Thanks a lot
If I understand correctly, to do this dynamically, i.e. for any sentence, you would need to program that using a script, like Node, PHP, Python etc…
You would need to split the sentence in to an array of multiple parts and then loop through that array, for each word create a clip and add to the start position. Something like below, (JavaScript but not tested):
let start = 0; // the very start of the video
let delay = 0.2; // default length
let length = 5; // the time to show the whole sentence once displayed
cons clips = []; // an array to hold all the clips that get created for each word.
const words = "this is my sentence".split(" "); // split the sentence to an array of words
words.forEach((word) => {
clips.push(.......) // create the clip here using word, start and length. You can use the SDK here or an object
start += delay; // start the next word 0.2 seconds after the previous word
length -= delay; // deduct 0.2 seconds from the length so all words show for the same time
});
// Add the clips array to a track, track to a timeline, etc... and POST to the API.
Something along these lines should do it.