I made a gif of me mashing the keyboard on hackertyper and it got me the idea of using this terminal as a welcoming animation!
So I wanted to give my blog a cool vibe while also looking good. I did not want it to be too overwhelming with effects, sliding animations and such. So I opted for something simple, it’s just text after all! But it’s also quite catchy and fun to watch.
So here is how I have achieved this effect, it’s nothing crazy hard really but I love playing with CSS and Javascript and so I did.
I started by looking for Javascript libraries that implemented the typewriter effect. I would rather go for pure javsacript than JQuery, even better if it’s a lightweight specific library that only includes that effect.
So I found Typewriter.js, which does exactly what I needed!
The challenge was of course to make sure it looked nice and smooth!
Creating the terminal typewriter
The basic HTML
The html is really simple, nothing to explain here. I just added a pipe ▌ character as default in the typing area so it does not look empty when the user loads the page and Typewriter has not started typing yet.
Now that we have our html structure we can start styling it and adding the actual typewriter to it!
Styling the terminal
I wanted to give it a terminal look, but also not a DOS look, something a bit more fancy and modern. So I started with a simple rounded rectangle with a nice dark gray background:
Terminal Example! The font is FiraCode <- -> != !== ==> |= ▌
(I LOVE this font, it’s amazing and it has some cool ligatures!) A few CSS tricks I learnt over the years:
transition: It animates any change to the specified property, in this case I am aimating opacity and max-height so whenever they change, their value is animated in 0.5s
font-family: I am using the CSS variable that Hydejack uses for the code blocks font family, just to be consistent with the rest of the website
box-shadow: This is a layered, high quality shadow generated with https://brumm.af/shadows
Start typing!
This is the best part of the project!
Now that we have everything set up we can start typing in text into the terminal. Let’s start by retreiving the container where the text will go
Ok so now that we have our container, we need to look for the typing area. It’s also a good idea to only start typing if the container exists, and do nothing otherwise.
We also need to make sure that the typing only starts when the page content is loaded. In the case of Hydejack (the Jekyll theme I am using), we need to account for dynamic page loading so:
Alright so let’s test it out, shall we?
Adding a status bar
Let’s try and give it more of a terminal look now by adding a Ubuntu-styled status bar. Let’s add a few divs for the bar and its buttons
Let’s style it up a little bit now. We want to use an inset shadow, and give a different color to the buttons. The only clickable button should be the closing button so let’s change it’s :hover: CSS and also add a disabled state.
Window Title
—
☐
✕
▌
Now for the final touch, let’s make it so that the close button actually closes the terminal, but we’ll enable the button after 10 seconds so there is time for some text to be typed in the terminal!
Window Title
—
☐
✕
▌
Heads up: Reload the page if you don’t see the terminal or if you closed it already!
The code is fairly simple:
Retreive the close button
Add an event listener to its click
Add an event listener to the typingWindowtransitionend
When It gets clicked, set the opacity of the window to 0
CSS will start the animation, when it’s over it will trigger the event transitionend
On the event handler we check if the opacity is below a certain threshold, if it is then the element is invisible and we can scale it down by setting its max-height to 0
When the transitionend is triggered again we’ll check if max-height is equal to 0px and if its we can remove the whole typingWindow from the DOM
Extras (looping, list of words, emojis)
Alright so here are a few extra tricks I implemented to save some time. I am also writing it down for me to remember. The way Typewriter.js works is by adding events to a queue. Calling pasteString()deleteChars() or pauseFor() will add those events to the queue, and they will be executed in order whenever start() is called. After that, we won’t be able to add any new event to the queue, we’ll only be able to stop() the typewriter.
I wanted my typewriter to keep changing the last few words in loop so I implemented a little trick without having to rewrite the library:
So the main idea is to have a list of words that keep being written and deleted, but I did not want to manually enter the char to delete every time. So by using a list I can delete the length of the previous word and type in the new one:
Create a list of words
Type the first part of the text (non looped)
Add a loop which types in and deletes each word from the list (including pauses)
Loop the previous loop for how many times you want. If you have 10 words with a delay of 2 seconds between each word, 100 loops will take ~2000 seconds, around half an hour.
TIP: You can use html to format your text, but don’t forget that deleteChars() of Typewriter expects the number of chars without counting html, so a simple string.length in javascript won’t work. You need to strip the string of the html and that’s where strip() comes in
Heads up: I tried with 100 loops and I noticed it would take a few seconds for the Typewriter to start, slowing down the page loading, so I use 20 loops
Adding a terminal typewriter to your page or post
Adding content to the blog page
So first thing I did was to allow for the Hydejack’s blog page layout to include content besides the list of post, so I copied the blog layout from hydejack and create a new layout file _layouts/blog__custom.html based on the base layout:
TIP: You can avoid Jekyll capturing liquid code by wrapping it in \{\% raw \%\} \{\% endraw \%\}
So you can see how I added {{ content | markdownify }} to the top to add whatever content I’ll write to any page using blog-custom as a layout.
Now that we can add content to the top of the blog page we can start creating our structure for the typewriter window:
Allowing for custom featured images in posts
I made a few changes to the Hydejack theme so that I could:
Display wide images as a post feature image
Display divs and javascript content as a featured post content (as you can see for this post)
For the first point I simply added custom classes for posts, I added a class property to the post image (aside from path). In order to use this new property I edited the _incudes/component/hy-img.html as below:
I simply always add classes to the img tag which are empty by default, in this way I am sure this will work with the pre-existing configuration. If I always added include.img.class when it did not exist I could have incurred into issues later, and I definitely wouldn’t want to remove include.class as it might be used in otehr cases. Furthermore, I did not want to add any style tag simply because I noticed the hy-img always end up with style="opacity: 0; in the final html page and I am not sure if that’s needed or not so I did not want to overwrite that.
Let’s not forget to add the CSS for dealing with wide featured images:
For the second point of displaying divss into post featured images, it was actually fairly simple. Sasme as before I added a new post image property called html, I then edited the file _includes/component/post.html so that if image.html is definied it will use the html instead of the image path. so I changed this :
To this:
Last touch, I added the console effect html to the post property which now looks something like this:
Beware that this only works in the post page or in the post preview, it will NOT work in the post card when showed as related post (you’d have to edit _includes/component/post-card.html for that). I would not recommend it as it makes everything more complicated and messy with loading randomg javascript all the time. For this reason I would suggest to have an image to display as a fallback option
Adding the javascript
When it comes to the post terminal I can simply add the javascript shown above in between the <script></script> tags. For the page, I added the javascript to the _includes/my-scripts.html. The event listeners will try to load the terminal at every page but the function returns if there is no element with classes typing-window blog.
IMPORTANT: When deploying jekyll with the command JEKYLL_ENV=production bundle exec jekyll build (to enable the search function) make sure that your javascript is PERFECT as in, add a ; to EVERY statement. Otherwise then it gets minified, something like
Becomes:
Generating an error and making your whole javascript code crash
An important note, if you end up using IDs instead of classes, multiple terminials on the same page might not work. The reason is that when Javascript calls getElementById() it always retreives one only element with that id. That’s the purpose of IDs, right? Uniquely identifying elements. If we want it to work for ANY html element with the class typing-window we need to use getElementByClass() as shown above.
Adding a description to your page terminal
You will notice I also added a little description to the typing window to link to this post, I simply wrapped the whole window in another div like this:
I then added some extra CSS to _sass/my-style.scss