The Best Way to Create Fantastic ‘Invisible Pen’ Effects in SVG

Share this article

Invisible Pen

Key Takeaways

  • Vivus.js is a lightweight JavaScript library that simplifies the process of creating complex SVG linework animations, including the ‘Invisible Pen’ effect. It offers advantages such as ease of use, automation, and flexibility.
  • The library provides five preset animation types, and the ability to control animation properties in a Vivus ‘constructor object’. It also automatically converts all SVG objects into path elements, making it easier to animate them.
  • With Vivus.js, designers can create complex and interesting animations without having to extensively manipulate CSS properties. Once the SVG document is ready, it can easily be turned into a working animation.
  • To install Vivus.js in a project, it can be added using npm or yarn, or the Vivus.js file can be downloaded from the GitHub repository and included in the HTML file. The library can be used with both React and Angular, and works on both desktop and mobile devices.
Invisible pen

From the BLINK tag of the early 90’s to today’s modern CSS3 transitions and animations, the ability to move elements on web pages/applications has been always a tempting goal.

Today, technologies like SVG make it relatively easy to create an effect that I’m going to call the ‘Invisible Pen’ effect. This is where the viewer watches an illustration appear line-by-line, as if drawn by an invisible pen.

The idea isn’t new. Back in 1953 in ‘Duck Amuck‘, an unseen hand (later revealed to be Bugs Bunny) famously torments poor Daffy Duck by constantly erasing and redrawing the world around him. It’s a surreal masterpiece.

Scene from Duck Amuck
Duck Amuck – 1953 – Directed by Chuck Jones

Fast forward to 2013, and Jake Archibald cleverly demonstrated how you could manipulate stroke-dashoffset, stroke-dasharray and some CSS to create this ‘magic pen effect’ on any SVG path.

Jake’s approach is easy to implement on relatively simple SVG linework, but it’s not always the ideal solution when we want to create something more complex. For more complicated linework animations there are purpose-built tools to help you such as Vivus.js. Vivus is a lightweight JavaScript library which allows us to animate the SVG elements without messing around too much with CSS.

I suppose the main question popping into your head now is: What makes Vivus better solution than the pure CSS approach?

In my opinion, Vivus has three main advantages which should be mentioned:

  1. Ease-of-use: In Vivus, we control most of our animation properties in a Vivus ‘constructor object’ and in context along with our SVG document. This makes changes more convenient and intuitive to work with. With only a couple of tweaks we can get a completely different animation result.

  2. Automation: As you may already know, SVG’s stroke-dashoffset property – the key to this effect – is only available on path elements. This can cause problems if your SVG drawing contains circle, rectangle, line, polyline or other common SVG ‘non-path’ objects.

    Fortunately, Vivus is smart enough to automatically convert all SVG objects into path elements making it possible for us to animate them too. This is a huge advantage.

    However, do note that we need to transform all text element manually into paths, using a vector editor such as Illustrator, InkScape, and alike.

  3. Flexibility: Vivus offers five preset animation types, along with a lot of options for manipulation, which gives us great flexibility about our animation’s behavior.

Now, let’s start exploring Vivus in more detail and see these advantages in action.

Attention designers: Yes, there is some code ahead, but Vivus is designed to be used by designers. Even if you’re not a hardcore codemonkey, a little cut, paste and edit will get you some pretty cool results.

Exploring Vivus

To start using Vivus we need to include it in our HTML like this:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vivus/0.3.2/vivus.js"></script>

Then, we can use an inline SVG in the following manner:

<svg id="canvas">
  <path...>
  <path...>
  <path...>
</svg>

And the script:

<script>
  new Vivus('canvas', {duration: 300}, callback);
</script>

Here, we have an inline SVG and a Vivus constructor function which takes three parameters:

  • ID of the DOM element we want to interact with (our ID is ‘canvas’).

  • An option object where we put all the animation options.

  • And an optional callback function called at the end of the animation.

Before we move on, we need to know the following:

  • By default Vivus draws elements in the same order as they are defined in the SVG document.

  • All SVG elements must have a stroke property and cannot be filled.

  • We must not put any hidden path elements in our SVG. Otherwise the animation might not be displayed properly.

  • Text elements cannot be converted into path elements. If you want to use text in our animation we need first to transform it into paths (in editor like Illustrator, InkScape).

The Five Drawing Options of Vivus

In the next sections we’ll explore all five animation types offered by Vivus. We’ll use a very simple drawing (four lines) in order to see clearer the difference between the available animation options.

Delayed

See the Pen Vivus demo: Simple line animation with delay by SitePoint (@SitePoint) on CodePen.

CodePen

Here our SVG drawing consists of four lines with equal length. In delayed mode, which is the default animation, all paths start almost simultaneously with a small delay between each one.

One-By-One

See the Pen Vivus demo: One-by-one by SitePoint (@SitePoint) on CodePen.

CodePen

In oneByOne mode each path is drawn one after the other. In the example above the same four lines are drawn one by one in a continuous manner.

Async

See the Pen Vivus demo: Asynchronous example by SitePoint (@SitePoint) on CodePen.

CodePen

In async mode each path is drawn asynchronously. In the example above lines with different lengths are used in order to see more clearly that lines start and finish at the same time regardless their different lengths.

Scenario

This and the next animation type give us ability to set animation properties directly in the DOM of the SVG. This allows us to gain more control over our animation and refine it much more precisely.

In scenario mode we just have to define the start time and duration of each path element with data-start and data-duration attributes. If it is missing, it will use the default value given to the constructor.

See the Pen Vivus Demo: ‘Scenario’: Custom line drawing speed by SitePoint (@SitePoint) on CodePen.

CodePen

In the example above the second line starts first, then the third line is drawn quickly, next the first line starts, and finaly, the last line starts when the first one is in the middle of its way and they both finish at the same time. Here is the simplified scheme of our SVG:

<line data-start="200" data-duration="200" .../>
<line data-start="0" data-duration="100" .../>
<line data-start="100" data-duration="10" .../>
<line data-start="300" data-duration="100" .../>

As we can see to direct our animation we just need to perform simple math calculations. And here is where the Vivus’ flexibility shines. We don’t have to respect the original order of the SVG. We can start with whichever element we wish and continue with all the others in whatever order we need.

Scenario-Sync

In scenario-sync mode, the default behavior is the same as in oneByOne mode. However, we can further refine the animation by targeting some attributes to specific path items such as:

  • data-duration – to define the duration of the path animation

  • data-delay – to define the delay between the end of the animation of the previous path and the start of the current path

  • data-async (no value required) – to make the drawing of the path asynchronous i.e. the next path will start at the same time. If a path does not have an attribute for duration or delay then the default values, set in the option object, will be used.

See the Pen Vivus Demo: Scenario sync by SitePoint (@SitePoint) on CodePen.

CodePen

In the example above the first line is drawn with the default duration of 200ms. The second line starts with a delay of 100ms and the same duration. The third line starts immediately after the second one and continues 300ms. Because the third line has data-async property, the last line starts at the same time as the third but finishes before it because it has a duration of 200ms.

Here is the simplified scheme of our SVG:

<line .../>
<line data-delay="100" .../>
<line data-duration="300" data-async .../>
<line data-duration="200" .../>

Complete Examples

Now, when we already understand the different types of animation offered by Vivus, it’s time to test them in a more practical and realistic way. In this section, we’re going to create two complete animations using the `delayed` and `scenario-sync` modes.

Car Blueprint Drawing

In the first example, we’ll create this blueprint from a Seat Leon:
Seat leon blueprint - Vecteezy.
Seat Leon blueprint – Source: Vecteezy.
The file (Free vector art via Vecteezy!) was opened in Illustrator and then exported as SVG. For the full SVG code, refer to the CodePen example at the end of this section. First, in our JavaScript file or <script> tag, we create a new Vivus constructor pointing to our SVG by using canvas ID. In the option object, we define the type of the animation to be delayed
and the timing function for the entire animation.

We use for that the built-in timing method Vivus.EASE. As a result, the animation will start and ends more gently. We also add a callback function which will reset the drawing three seconds after the animation end and then will draw it again.

new Vivus('canvas', {
	  start: 'autostart', 
	  type: 'delayed', 
	  animTimingFunction: Vivus.EASE
	  }, 
	  function(car){
	    setTimeout(function(){ car.reset().play(); }, 3000);
	  }
	);
You can see the final result here:

See the Pen Vivus Example: Car blueprint by SitePoint (@SitePoint) on CodePen.

As you can see, we get an amazing blueprint animation effect with minimum effort from our side.

Rocket Drawing

In the second example, we’ll create a rocket illustration animation and integrate color. Simple rocket Our goal is to draw the rocket, fill it, and then remove the stroke. For the SVG code refer to the CodePen example at the end of this section. We start again with a new Vivus constructor. This time we set the type of animation to scenario-sync and set pathTimingFunction to Vivus.EASE_OUT. We use a callback function which will add some CSS classes at the end of the animation. They will fill the rocket and will remove its strokes.
new Vivus('canvas', {
	  start: 'autostart', 
	  type: 'scenario-sync', 
	  pathTimingFunction: Vivus.EASE_OUT
	  }, 
	  function(obj){
	    obj.el.classList.add('fill-1', 'fill-2', 'fill-3', 'fill-4', 'fill-5', 'fill-6', 'fill-7', 'clear-stroke');
	  }
	);
In our CSS file or <style> tag we initially set the path’s fill-opacity to zero and a transition for it with duration of 1s. Then we use CSS selectors to assign fill property for each element in the SVG and make it visible by setting the fill-opacity to 1. You can read more about this trick here. And finally, we set the stroke for each path to none.
path {
	  fill-opacity: 0;
	  transition: fill-opacity 1s;
	}

	.fill-1 g:first-of-type > path{
	  fill: #1c8ece;
	  fill-opacity: 1;
	}

	.fill-2 g:last-of-type > path{
	  fill: #ffffff;
	  fill-opacity: 1;
	}

	.fill-3 path:first-of-type{
	  fill: #f4a260;
	  fill-opacity: 1;
	}

	.fill-4 path:nth-of-type(2){
	  fill: #ea3e2f;
	  fill-opacity: 1;
	}

	.fill-5 path:nth-of-type(3){
	  fill: #d1d2d4;
	  fill-opacity: 1;
	}

	.fill-6 path:nth-of-type(4), 
	.fill-6 path:nth-of-type(5) {
	  fill: #000000;
	  fill-opacity: 1;
	}

	.fill-7 path:nth-of-type(6){
	  fill: #ffffff;
	  fill-opacity: 1;
	}

	.clear-stroke path{
	  stroke: none;
	}
In our SVG, we use data-duration and data-delay properties to build the animation according to our needs. data-async property is used to make the two wings of the rocket are drawn simultaneously. Here is the simplified scheme of the SVG:
<path data-duration="50" .../> 
<path data-duration="150" data-delay="100" .../> 
<path data-duration="50" .../> 
<path data-duration="50" .../> 
<g> <polygon data-duration="300" data-async .../> 
<polygon data-duration="300" .../> 
</g> <path data-delay="25" .../> 
<path .../> 
<g> <polygon data-async .../> <polygon .../> </g>
You can see the final result here:

See the Pen Vivus Example: Rocket by SitePoint (@SitePoint) on CodePen.

Summary

As you can see, with Vivus we can concentrate primarily on our drawing idea and its practical realization, instead of juggling with CSS properties. Once we have our SVG document ready, it’s a relatively simple process to turn it into a working animation.

With a little bit of imagination and the animation capabilities of Vivus, we can create complex and interesting animations in no time.

Frequently Asked Questions about Creating the Invisible Pen Effect in SVG using Vivus.js

How can I install Vivus.js in my project?

To install Vivus.js in your project, you can use npm or yarn. If you’re using npm, run the command npm install vivus. For yarn, use yarn add vivus. After installation, you can import it into your project using import Vivus from 'vivus';. Alternatively, you can download the Vivus.js file from the GitHub repository and include it in your HTML file using the script tag.

Can I use Vivus.js with React or Angular?

Yes, Vivus.js can be used with both React and Angular. You can import the Vivus library into your component and use it to animate SVGs. However, you may need to use a wrapper or a custom directive to make it work seamlessly with these frameworks.

How can I control the speed of the animation?

The speed of the animation can be controlled using the duration parameter in the Vivus constructor. The duration is specified in milliseconds. For example, new Vivus('my-svg', {duration: 200}); will create an animation that lasts for 200 milliseconds.

Can I animate SVGs that are not in the DOM?

No, Vivus.js requires the SVG to be in the DOM to animate it. If your SVG is not in the DOM, you will need to add it before you can animate it with Vivus.js.

How can I make the animation start automatically?

By default, Vivus.js animations start when the SVG is in the viewport. If you want the animation to start automatically, you can set the start option to ‘autostart’ in the Vivus constructor. For example, new Vivus('my-svg', {start: 'autostart'});.

Can I use Vivus.js to animate SVGs on mobile devices?

Yes, Vivus.js works on both desktop and mobile devices. However, keep in mind that complex animations may not perform well on older or less powerful devices.

How can I repeat the animation?

To repeat the animation, you can use the reset method to reset the SVG to its original state, and then call the play method to start the animation again. For example, myVivus.reset().play();.

Can I animate a part of the SVG?

Yes, you can animate a part of the SVG by using the pathTimingFunction option in the Vivus constructor. This function determines the animation timing for each path in the SVG.

How can I change the color of the SVG during the animation?

Vivus.js does not provide a built-in way to change the color of the SVG during the animation. However, you can use CSS animations or JavaScript to change the color of the SVG paths during the animation.

Can I use Vivus.js with other animation libraries?

Yes, Vivus.js can be used in conjunction with other animation libraries like GSAP or Anime.js. However, keep in mind that using multiple animation libraries may increase the complexity of your code and the load time of your website.

Ivaylo GerchevIvaylo Gerchev
View Author

I am a web developer/designer from Bulgaria. My favorite web technologies include SVG, HTML, CSS, Tailwind, JavaScript, Node, Vue, and React. When I'm not programming the Web, I love to program my own reality ;)

AlexWinvisible penmagic penSVGvivus.js
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week