Write a Short Story With SVGs and Vue.js (Reviving Zelda-Like Nostalgia)

Michael Mangialardi
Coding Artist
Published in
22 min readMar 1, 2017

“Pondering over the wall that he saw, he pulled out the pencil and tried to draw. Once Cover finished his shape, he proceeded forward looking for an escape.”
— Pencil & Eraser, A Short Story by Mike Mangialardi

What you’re getting into: A lengthy, detailed post on how I got the idea for creating a short story using SVGs and Vue.js and actionable tips on how to create your own.

Self-promotion: If you like this, I have a premium video course on making fun Vue.js apps that goes into much more detail on learning Vue.js with an emphasis on design and creativity.

(Update 3/27/17): I have begun the process of creating a video course for providing a very clear and detailed break down of SVGs. I will cover explaining SVGs “under the hood”, using Affinity Designer to create detailed vector graphics, animation with CSS, GreenSock, Mo.js, and Anime.js, as well as some practical applications of UX animations. You can book access here.

My short story/demo: http://codepen.io/mikemang/pen/9a6c3e64324d5c5d0ac5732096f9356c/?editors=1010

A Revival of Nostalgic Adventure

Can you think back on a story or video game when you felt the sense of adventure? For me, I tend to think back about my days as a child when I played Pokemon Blue, Ocarina of Time, and Paper Mario. These were some of my favorite games growing up the blew me away by their ability to animate a strong sense of adventure and exploration.

Particularly, Ocarina of Time was able to stir such captivation by its immense open world. There is still something so nostalgic when I think about that experience of riding along the green pastures outside of Hyrule.

The Legend of Zelda: Ocarina of Time

Whatever video game came to your mind, I’m sure there’s much nostalgia circulating in your mind. If you’re like me, these sorts of reflections stimulate such an immense sense of curiosity. I’m so intrigued by how the creators of Ocarina of Time were able to envision such delightfully immense, beautiful, and adventurous world.

I have long wished to create such a world with my own imagination and ideas. Despite some dabbling to writing, like 25 pages worth of a zombie novel, I have yet accomplished this desire within me.

Lately, I have realized that it makes more and more sense why I ended up a frontend developer with a heavy emphasis on design. This type of work forces me to tap into my well of creativity and imagination. The more I begin to realize this, the more I am trying to make conscience efforts to improve my creativity.

One of the ways I have been trying to do this is by completing exercises through The Imagineering Workbook, a workbook full of “out of the box” exercises created by the people at Disney. One day, I had the idea of writing a children’s book as another way to exercise my creativity, especially since children books are very design friendly. With this in mind, my wife and I went to Barnes & Noble, and I specifically was looking for a book to provide some structure for accomplishing this. In the bargain section, I found the perfect match, a book titled Children’s Writer’s Notebook | 20 Great Authors & 70 Writing Exercises. This books summarizes the writing themes of many successful authors of children stories, like Dr. Seuss, C.S. Lewis, Ronald Dahl, and more, and provides related exercises based on these themes.

I was pumped to get home and start started on doing these exercises and eventually writing a children’s book. Before I left the store, however, another book caught my eyes, The Legend of Zelda | Arts & Artifacts, a massive collection of illustrations from The Legend of Zelda series.

Suddenly, that dormant desire within me since playing Ocarina of Time to create a powerfully imaginative world through visuals and stories was revived. I put on a YouTube playlist of Fantasy music, sorted through Zelda artwork, and attempted to let my imagination run wild in attempts to create a short story that I would with SVGs and Vue.js. By the end of the day, I had achieved my goal. While just a small step towards my end goal, it was still one of the greatest creative exercises I had ever done that I am excited to try out again. However, before I do that, I wanted to share how to do this exercise with all of you.

Step 1: Reviving Your Own Zelda-Like Nostalgia

Embarking on a creative exercise of this sort requires a lot of imagination. While there are many ways to go about writing a short story, I will be listing the steps that I took.

Earlier, I asked if you could recall a story or video game that sparked a sense of adventure. The reason I started with this is because this could be the first step to retrieving the imagination you need to create a short story.

Revive the nostalgia and try to picture all that you can remember. Imagine the environment, sound, colors, etc. What do you think made it so memorable?

After you do this, try to brainstorm your own ideas for a setting and visuals for your own story. You can look at artwork for assistance in this process. For me, this was looking at Zelda artwork.

Once you have an idea for a setting, a character, and some different scenes in mind, you can move forward to the next step.

Step 2: Outlining the Story

Once you have a mental picture of your visuals, the next step is to start writing a brief synopsis of the story, a description of the environment, and a brief description of the character(s).

If you really need help getting started, a broad synopsis can be a boy entering some journey in the setting you visualized and returning home safely. Ask yourself: How did he leave? What did he encounter? How did he return?

Example:

Summary:

_____ is a young boy of brilliance, but in the midst of academia, his mind begins to wander to far off places of fantasy and adventure

While reading a book, his mind begins to wander to a mysterious island full of bright green vines and brightly colored blocks light under a full moon.

On the island, he realizes that everything is a puzzle, his only possession is a magic pen.

With the pen he has the power to create shapes, he is left to navigate through the island by using shapes that keep him safe.

He discovers a final twist that leaves him scared, but by mustering the courage, he conquers his fear and finds his way back home safe.

He is interrupted by his mother which wakes him up from his dream. He looks at a computer and realizes it is a dream he better write if he wants to keep.

Entrance

_____ reads and drifts into a fantastical dream.

Exit

_____ wakes up from his dream.

Now, it is important to remember that a short story that is heavily visual, like we want to create, does not require many words. The cap for this short story should be 250 words.

With this draft written, the next step is not writing the story, but rather creating the visuals.

Step 3: Creating the Visuals

I created all vector graphics in Affinity Designer. If you have not made vector graphics before then the next thing to do is check out my beginner’s guide to vector graphic design. When you finish reading that, or if you already know how to make vector graphics, you can continue on.

With an outline of a story in mind, you can then get to work creating the visuals. Personally, I did this while listening to a fantasy playlist to get me in a mood of concentration.

I also was looking at the same artwork from step 1 to assist with ideas for making the visuals.

Here is the image that really inspired my first scene:

My story was about a boy who falls asleep and begins to drift into a dream. As he transcends into the dream, he sees just a circle in the midst of a dark background that is a glimpse of where his dream was leading him.

The first visual I created was crucial as it leads the way for the color palette that would be used throughout my story.

I got these color choices by using Dribbble and Coolors as inspiration. I really liked how the first visual looked as it really captured what I had pictured in my mind. So, I went ahead and organized my hex codes.

Any easy way to do this is by using an automatic generator from an image via Coolors.

To do this, click the camera icon under the Generate tab and upload an image:

Then, it will detect your colors and allow you to make changes if needed:

Hit Ok and you should have all the hex codes laid out:

You can also get different shades of these colors in case you need more variety.

Once I had my color palette set, the next step was creating the characters. My story only had one character called Cover. His head was a book with overlaying circles for eyes and a simple body.

My recommendation for the characters, and really the entire short story, is to keep it simple. Don’t overthink it. You just need to think about what shapes you can put together to create a character. For practice, you can try breaking down all the shapes of my character. Then, take a look at characters from your sources of inspiration and try to break them down into shapes. Eventually, you should have an idea of constructing your own character out of shapes.

Once you create the character, the next step is just to compose the scenes that you had brainstormed in your mind. Again, make sure to keep it simple and break down the scene into various components and the shapes that make up those components.

Let’s take a look at one of my scenes:

This scenery here is quite simple.

I used 3 separate rectangles of different sizes to create the steps on the left and right. Inspired from Zelda, I had torches hanging to side of an archway. The archway is simply a rectangle with the top corners rounded down. The torches are just a long triangle on the bottom with another triangle on top.

The triangle on top is curved slightly on one side. To do this in Affinity Designer, draw out a triangle:

Select the triangle and click Convert to Curves:

You can then select the node tool and apply the curve like so:

Next, I just add a thin rectangle to represent a wooden frame holding the torch in place.

Then, I placed my character in the middle and completed the scene:

Once you do your first scenery, the rest of the scenes can be very similar. Let your imagination run and create the scenes for your story.

As I mentioned earlier, I enjoyed creating the visuals before I wrote the actual text for the story. This gave me the ability to let the visuals drive the story I had outlined. As I created the visuals, the story began to unfold more in my mind.

Make sure to be saving all the files for the visuals as you go along.

Step 4: Exporting the Visuals

First off, if you are not familiar with exporting vector graphics as SVGs and importing them on the web, here’s a detailed guide titled Take Vector Graphics to the Web (An Introduction to SVGs).

When you are ready, we can continue on.

Once you have all the files for the visuals that you need to write the story saved, the next thing I did was group all the major components together in Affinity Designer.

I grouped them to be optimized for animation. In this scene, I separated the flame from the flame base so that I could identify the flame and add animation to it while the other components would be static.

If you just want to have static scenes for your story, you don’t have to worry about grouping. However, it is a good habit to get into.

Once each scene has been grouped as needed, you can export them as SVGs. Important: Make sure to have a consistent naming convention like scene [number]. This will be very important later on in this tutorial.

Step 5: Setting Up the Codepen Project

With all the SVGs saved, it’s time to set up our Codepen project for importing the SVGs.

There are 3 major components that will make up our short story app, text (a title and subtitle), a box that will contain the SVGs, and a button for going on to the next scene.

By using Vue.js, the text and SVGs can be dynamically controlled. Meaning, we will be able to toggle on and off our SVG scenes and update the text on the click of the button.

We will get to the fun Vue.js stuff later, but for now, let’s set up some static text, box, and button in your pen. Note: Use the CSS preprocessor, SCSS.

HTML

<div id="text">
<div class="title">Title</div>
<div class="sub-title">Subtitle</div>
</div>
<div class="box">
</div>
<div class="button">
Begin
</div>

CSS

//import this at top using SCSS preprocessor
@import url('https://fonts.googleapis.com/css?family=Lato:100,300,400,700');
body{
background: #010915;
}
.box{
position: relative;
display: block;
margin: auto;
margin-top: 3%;
width: 500px;
height: 400px;
border: solid 1px white;
}
.title{
position: relative;
margin-top: 2%;
margin-bottom: 2%;
font-family: "Lato";
color: #86D3DF;
font-size: 40px;
font-weight: 700;
text-align: center
}
.sub-title{
position: relative;
margin-top: 2%;
margin-bottom: 0%;
font-family: "Lato";
color: white;
font-size: 20px;
font-weight: 100;
text-align: center
}
.button{
cursor: pointer;
position: relative;
padding: 10px 15px;
background: #86D3DF;
display: block;
margin: auto;
margin-top: 1%;
width: 200px;
font-family: "Lato";
color: #010915;
font-size: 20px;
font-weight: 400;
text-align: center;
text-transform: uppercase;
}
@media all and (max-width: 600px) {
.box{
margin-top: 100px;
margin-bottom: 20px;
width: 250px;
height: 175px;
}

}

We should now have:

Go ahead and adjust the color scheme to your liking. Then, you can also update the texts, although we will be changing this shortly.

Next, you can get the code for one of your SVG files and paste it within the box:

<div class="box">
<svg width="100%" height="100%" viewBox="0 0 792 612" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"><rect id="Background" x="0" y="0" width="792" height="612" style="fill:#010915;"/><path id="Door" d="M577.44,345.36c0,-100.207 -81.233,-181.44 -181.44,-181.44c0,0 0,0 0,0c-100.207,0 -181.44,81.233 -181.44,181.44c0,124.246 0,266.64 0,266.64l362.88,0c0,0 0,-142.394 0,-266.64Z" style="fill:#35699a;fill-opacity:0.298039;"/><g id="Flame-Base-Left"><rect x="57.36" y="280.8" width="149.52" height="6.72" style="fill:#86d3df;"/><path d="M132.12,364.44l-21,-95.16l42,0l-21,95.16Z" style="fill:#35699a;"/></g><path id="Flame-Left" d="M132.12,227.52c10.644,8.739 16.582,24.169 21,41.76l-42,0c7.874,-9.083 13.777,-19.921 21,-41.76Z" style="fill:#86d3df;"/><g id="Flame-Base-Right"><rect x="589.68" y="280.8" width="149.52" height="6.72" style="fill:#86d3df;"/><path d="M664.44,364.44l21,-95.16l-42,0l21,95.16Z" style="fill:#35699a;"/></g><path id="Flame-Right" d="M664.44,227.52c-10.644,8.739 -16.582,24.169 -21,41.76l42,0c-7.874,-9.083 -13.777,-19.921 -21,-41.76Z" style="fill:#86d3df;"/><g id="Steps-Left"><rect x="143.76" y="514.56" width="70.8" height="97.44" style="fill:#86d3df;"/><rect x="143.76" y="417.12" width="70.8" height="97.44" style="fill:#86d3df;"/><rect x="72.96" y="563.28" width="70.8" height="48.72" style="fill:#86d3df;"/><rect x="72.96" y="514.56" width="70.8" height="48.72" style="fill:#86d3df;"/><rect x="72.96" y="465.84" width="70.8" height="48.72" style="fill:#86d3df;"/><rect x="0" y="538.92" width="72.96" height="73.08" style="fill:#86d3df;"/></g><g id="Steps-Right"><rect x="577.44" y="514.56" width="70.8" height="97.44" style="fill:#86d3df;"/><rect x="577.44" y="417.12" width="70.8" height="97.44" style="fill:#86d3df;"/><rect x="648.24" y="563.28" width="70.8" height="48.72" style="fill:#86d3df;"/><rect x="648.24" y="514.56" width="70.8" height="48.72" style="fill:#86d3df;"/><rect x="648.24" y="465.84" width="70.8" height="48.72" style="fill:#86d3df;"/><rect x="719.04" y="538.92" width="72.96" height="73.08" style="fill:#86d3df;"/></g><g id="Book-Man"><g><path d="M489.545,525.465c0,-8.922 -7.233,-16.155 -16.155,-16.155c-14.835,0 -34.527,0 -34.527,0l0,16.155l50.682,0c0,0 0,0 0,0Z" style="fill:#35699a;"/><path d="M473.39,509.31c4.285,0 8.394,1.702 11.423,4.732c3.03,3.029 4.732,7.138 4.732,11.423c0,7.369 0,14.478 0,14.478l-16.155,0l0,-30.633c0,0 0,0 0,0Z" style="fill:#35699a;"/><path d="M495.459,538.384c0,-2.602 -2.113,-4.715 -4.715,-4.715l-18.553,0c-2.602,0 -4.715,2.113 -4.715,4.715l0,9.429c0,2.603 2.113,4.715 4.715,4.715l18.553,0c2.602,0 4.715,-2.112 4.715,-4.715l0,-9.429Z" style="fill:#35699a;"/></g><path d="M395.519,589.931l-34.78,0c0,0 0,-35.651 0,-64.201c0,-9.273 3.683,-18.166 10.24,-24.723c6.557,-6.557 15.45,-10.24 24.723,-10.24c0,0 0,0 0,0c30.658,0 55.511,24.853 55.511,55.51l0,43.654l-34.78,0l0,-21.465c0,-1.831 -0.727,-3.588 -2.022,-4.882c-1.295,-1.295 -3.051,-2.023 -4.882,-2.023c-2.283,0 -4.823,0 -7.106,0c-1.831,0 -3.587,0.728 -4.882,2.023c-1.295,1.294 -2.022,3.051 -2.022,4.882l0,21.465Z" style="fill:#86d3df;"/><rect x="296.57" y="381.578" width="218.811" height="117.843" style="fill:#373c42;"/><path d="M401.389,499.421l-35.042,0c-3.098,0 -5.608,2.511 -5.608,5.608c0,12.914 0,43.65 0,43.65l90.474,0c0,0 0,-27.667 0,-41.531c0,-2.049 -0.814,-4.015 -2.263,-5.464c-1.449,-1.449 -3.415,-2.263 -5.464,-2.263l-32.923,0l-4.587,6.139l-4.587,-6.139Z" style="fill:#e6e6e6;"/><path d="M416.433,589.931c0,0 26.023,0 42.783,0c7.639,0 13.831,6.193 13.831,13.832c0,0 0,0 0,0c0,4.549 -3.687,8.237 -8.237,8.237c-15.703,0 -48.377,0 -48.377,0l0,-22.069Z" style="fill:#35699a;"/><path d="M395.519,589.931c0,0 -27.882,0 -45.38,0c-3.668,0 -7.186,1.458 -9.78,4.051c-2.594,2.594 -4.051,6.112 -4.051,9.781c0,0 0,0 0,0c0,4.549 3.688,8.237 8.237,8.237c16.271,0 50.974,0 50.974,0l0,-22.069Z" style="fill:#35699a;"/><g><g><path d="M287.689,501.542l-0.074,-10.281l35.005,-0.253l0.075,10.281l-35.006,0.253Z" style="fill:#35699a;"/><path d="M287.639,494.621l-0.024,-3.36l35.005,-0.253l0.025,3.36l-35.006,0.253Z" style="fill:#4f789f;"/><path d="M287.664,498.081l-0.024,-3.36l35.005,-0.253l0.025,3.361l-35.006,0.252Z" style="fill:#6085a8;"/><path d="M287.689,501.542l-0.024,-3.36l35.005,-0.253l0.025,3.36l-35.006,0.253Z" style="fill:#4f789f;"/><path d="M276.618,496.481l11.071,5.061l-0.074,-10.281l-10.997,5.22Z" style="fill:#86d3df;"/><path d="M276.618,496.481l4.685,2.142l-0.031,-4.351l-4.654,2.209Z" style="fill:#010915;"/></g></g><g><path d="M310.605,513.969c0,4.284 1.702,8.393 4.732,11.423c3.029,3.029 7.138,4.731 11.422,4.731c14.654,0 33.98,0 33.98,0l0,-16.155l-50.134,0c0,0 0,0.001 0,0.001Z" style="fill:#35699a;"/><path d="M326.585,530.123c-4.238,0 -8.303,-1.683 -11.3,-4.68c-2.996,-2.997 -4.68,-7.061 -4.68,-11.299c0,-7.431 0,-14.654 0,-14.654l15.98,0l0,30.633c0,0 0,0 0,0Z" style="fill:#35699a;"/><path d="M304.755,501.05c0,2.602 2.113,4.715 4.715,4.715l18.25,0c2.602,0 4.715,-2.113 4.715,-4.715l0,-9.43c0,-2.602 -2.113,-4.715 -4.715,-4.715l-18.25,0c-2.602,0 -4.715,2.113 -4.715,4.715l0,9.43Z" style="fill:#35699a;"/></g><g><rect x="405.976" y="381.578" width="109.406" height="123.363" style="fill:#86d3df;"/><rect x="296.57" y="381.578" width="109.406" height="123.363" style="fill:#86d3df;"/><rect x="403.325" y="381.578" width="5.302" height="123.363" style="fill:#010915;"/></g><path d="M416.433,589.931l0,22.069l-20.914,0l0,-22.069l20.914,0Z" style="fill:#35699a;fill-opacity:0.298039;"/><path d="M395.519,589.931l0,-21.465c0,-1.831 0.727,-3.588 2.022,-4.882c1.295,-1.295 3.051,-2.023 4.882,-2.023c2.283,0 4.823,0 7.106,0c1.831,0 3.587,0.728 4.882,2.023c1.295,1.294 2.022,3.051 2.022,4.882l0,21.465l-20.914,0Z" style="fill:#35699a;fill-opacity:0.298039;"/></g></svg>
</div>

Using my code, we get this:

Awesome! We now have a basic starting point for our short story. Next, we will add the Vue.js so we can make this application dynamic.

Step 6: Setting Up the Vue.js

First things first, make sure to add Vue to your Codepen project like so:

Next, we will create the shell of some Vue instances. We will have one Vue instance for each of our main components which are the text (title and subtitle), the scene container, and the button.

JS

var text = new Vue({
el: "#text",
data: {

},
methods: {

}
})
var button = new Vue({
el: "#button",
data: {

},
methods: {
}})var scene = new Vue({
el: "#scene",
data: {

},
methods: {

}
})

Now, we can add the div tags in our HTML to make the association with these Vue instances:

HTML

<div id="text">
<div class="title">Title</div>
<div class="sub-title">Subtitle</div>
</div>
<div id="scene">
<div class="box">
</div>
</div>
<div id="button">
<div class="button">
Begin
</div>
</div>

Next, let’s add some data in our Vue instances that we can use in our HTML:

JS

var text = new Vue({
el: "#text",
data: {
title: "Pencil & Eraser",
subtitle: "A short story made with SVGs and Vue.js by Mike Mangialardi"

},
methods: {

}
})
var scene = new Vue({
el: "#scene",
data: {

},
methods: {

}
})
var button = new Vue({
el: "#button",
data: {
buttonText: "Begin"
},
methods: {
}})

Going back to our HTML, we can inject title and subtitle in our text component like so:

HTML

<div id="text">
<div class="title">{{title}}</div>
<div class="sub-title">{{subtitle}}</div>
</div>

We can also inject our button text:

HTML

<div id="button">
<div class="button">
{{buttonText}}
</div>
</div>

We now have the following controlled by Vue.js:

Before we continue, I wanted to explain how we are going to control the handling of switch scenes (switching SVG that renders). This is going to determine what data we have in our scene instance.

There are a couple of ways in which we could do this.

1) We could get URLs for our SVGs and then insert the URL in the SRC of an img tag like so:

<img src="*insert SVG URL here*" />

We could have this img tag in one Vue instance called scene. We could control the URL of the SRC dynamically using v-bind:src= “[data in Vue instance that is set to a value of an SVG URL]”. When a user clicks the button, we could have the SVG URL be updated for the next scene.

2) We could have multiple Vue instances with the name of scene[number]. We can add conditional rendering by using v-if= “[some boolean flag” that would control which scene renders. Each scene would have the long SVG code like we pasted earlier. When a user clicks the button, the instance for the current scene would be toggled off and an instance with the SVG code for the next scene would be toggled on.

We are going to go with option 1 as it will allow us to easily just change the URL for the current SVG instead of having to have a Vue instance for each scene which can make our code quite lengthy.

There is a disadvantage to this option. Since we won’t have the SVG code, we won’t be able to add CSS classes to specific shapes. For example, I won’t be able to add a CSS class with animation for my flames in my scenes. However, this isn’t a big concern since we don’t want to make things too bloated for this already lengthy post. It is better to keep things as simple as possible with your first short story.

First, let’s get URLs for our SVGs and set things up so it is being controlled with Vue.js.

If you have a Codepen Pro account, get the URLs for out SVGs will be really easy (or else you will have to find an alternative, without the other cool benefits). We can simply drag and drop our exported SVG files for our scenes in groups of 10:

Once we have the URL, we can replace the lengthy SVG code under our box class and insert an img tag like so:

HTML

<div id="scene" v-if="showScene">
<div class="box">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%207.svg" />
</div>
</div>

Now, let’s set this up our URL is dynamically controlled in the scene Vue instance.

JS

var scene = new Vue({
el: "#scene",
data: {
svgScene: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%207.svg"
},
methods: {

}
})

Here, we pasted the URL into some data called svgScene.

Next, let’s let out HTML we want the SRC to be controlled by our scene instance.

HTML

<div id="scene" v-if="showScene">
<div class="box">
<img v-bind:src="svgScene" />
</div>
</div>

We should now have the SRC being dynamically controlled with Vue:

Cool beans!

Now, we will add an event handler to call a function in our button instance. We will also define the function to handle the event.

HTML

<div id="button">
<div v-on:click="processClick" class="button">
{{buttonText}}
</div>
</div>

JS

var button = new Vue({
el: "#button",
data: {
buttonText: "Begin"
},
methods: {
processClick: function(){


}

}
})

So, how will we handle the click of a button?

Let’s think about what we need to do on the click:

  1. Keep track of what click/scene we are on so we can handle accordingly
  2. Change the value of svgScene to be the next SVG URL for the next scene in our scene instance
  3. Update buttonText to “Next” in our button instance
  4. Update the title and subtitle in the text instance

First, let’s add some data in our button instance called count which we will use to keep track of which click/scene we are on:

JS

var button = new Vue({
el: "#button",
data: {
buttonText: "Begin",
count: 0
},
methods: {
processClick: function(){


}
}
})

Next, let’s increment the count in processClick each time it is called:

JS

var button = new Vue({
el: "#button",
data: {
buttonText: "Begin",
count: 0
},
methods: {
processClick: function(){
this.count++

}
}
})

So, how do we handle the change of the SRC depending on the value of count?

Well, you could do a long segment of if/else if statements or a switch statement and have the svgScene be updated to contain the URL for each scene.

Fortunately, there’s an easier way to handle this as long as you named your SVG files with a naming convention that was consistent and specified the number of the scene.

Let’s take a look at the SVG URL:

https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%207.svg

I had named my SVG files as Section 1, Section 2, etc. The URL I used for my the cover (since the story doesn’t start until a user hits begin) was the same SVG as Section 7, hence Section%207. If we change Section%207 to Section%201, we will see the first scene which I titled Section 1.

This will make the handling of our SVGs on a click really easy:

JS

var button = new Vue({
el: "#button",
data: {
buttonText: "Begin",
count: 0
},
methods: {
processClick: function(){
this.count++
scene.svgScene = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%20" + this.count + ".svg"
}
}
})

First, we specify we want to change svgScene which is outside of the button instance so we to scene.svgScene.

Then, we just concatenated the URL so that it will load Section [count]:

https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%20" + this.count + “.svg//this is equal to
https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%20[insert count here].svg
//if count = 1, it will load Section 1
https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%201.svg
//if count = 2, it will load Section 2
https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%202.svg

Now, clicking the button will update the SVG for each scene:

Super cool!

Let’s review what’s left:

  1. Update buttonText to “Next” in our button instance
  2. Update the title and subtitle in the text instance

This next step is really easy:

JS

var button = new Vue({
el: "#button",
data: {
buttonText: "Begin",
count: 0
},
methods: {
processClick: function(){
this.count++
scene.svgScene = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%20" +this.count + ".svg"
this.buttonText = "Next"
}
}
})

Let’s also add some logic so the story restarts if there are no more scenes left. In my case, I have 21 different scenes so I did:

JS

processClick: function(){
this.count++
if(this.count == 22) {
this.count = 1
}

scene.svgScene = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%20" +this.count + ".svg"
this.buttonText = "Next"
}

Since there are 21 scenes, on the 22nd click count will reset to 1, so the scene 1 svg renders.

All we have left now is:

  1. Update the title and subtitle in the text instance

We will return to this shortly.

Step 7: Writing the Text

Now that you can click through your entire story, it’s time to write the text for each scene.

Again, try to keep the total story to a limit of 250 words. For an added challenge, you can try to make it rhyme (you may need a rhyming dictionary).

Jot down all your lines as you will need to copy and paste them later.

Step 8: Updating the Text With Vue.js

Once you have your text, it’s time to knock out the last piece of this short story!

First, we can update the title in the processClick function. The title will simply be the current scene (i.e. Scene 1).

JS

var button = new Vue({
el: "#button",
data: {
buttonText: "Begin",
count: 0
},
methods: {
processClick: function(){
this.count++
if(this.count == 22) {
this.count = 1
}
scene.svgScene = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%20" +this.count + ".svg"
this.buttonText = "Next"
text.title = "Scene " + this.count
}
}
})

This line will use concatenation like before to output Scene [count] (i.e. Scene 1, Scene 2, etc.) With one line, we can dynamically update the title in our text instance. Pretty cool!

Now, we need to update subtitle to be the text you wrote for each scene. We can also control this with one line of code, but it will require a bit more work.

First, we need to create an array that stores all the lines used in the story in our text instance:

JS

var text = new Vue({
el: "#text",
data: {
title: "Pencil & Eraser",
subtitle: "A short story made with SVGs and Vue.js by Mike Mangialardi",
lines: ["Cover opened a book to read, but quickly his eyes shut as he began to sleep.", "His imagination flowed like a running fountain and in the distance, he saw a mountain.", "Behold a mountain it could not be, but a pencil glowed as if destiny.", "Cover pulled with all the strength that he had until the pencil fit firm in his hand.", "Cover walked to a wall far-out, only to find there was no way out.", "Pondering over the wall that he saw, he pulled out the pencil and tried to draw.", "Once Cover finished his shape, he proceeded forward looking for an escape.", "Shortly, he stood in awe for if he continued he would fall.", "Cover grabbed his pencil once more and proceeded to draw a floor.", "Continuing to draw so he could proceed, Cover beheld an eraser as if destiny.", "Despite being weighed down like an anchor, Cover was able to pull out the eraser.", "Finding another wall far-out, Cover proceeded to draw his escape route.", "Passing through a corridor, Cover continued by drawing another floor.", "Pulling out his pencil to draw, he soon discovered it wouldn't work at all.", "Returning to the corridor and drawing a ladder, Cover hoped to solve the matter.", "Cover erased the wooden frame and now possessed a burning flame.", "Climbing the steps and creating flames, Cover now hoped he could draw away.", "Cover drew another shape and hoped he had finally escaped.", "Now escaped, Cover stood with awe and discovered an urge to continue to draw.", "Disappointed, Cover found himself awake and back to his dream he wished to escape.", "To his desk, Cover made his way hoping to write about a mountain far away. Behold a dream he longed to savor for what fun he had with a pencil and eraser."]
},
methods: {

}
})

This may seem like a lot, but now we can easily access the line we need. In our processClick function, we will only need to add one line:

JS

processClick: function(){
this.count++
if(this.count == 22) {
this.count = 1
}
scene.svgScene = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/827672/Section%20" +this.count + ".svg"
this.buttonText = "Next"
text.title = "Scene " + this.count
text.subtitle = text.lines[this.count - 1]
}
}

We do one less than count since array indexing starts at 0 and not 1.

Our short story is now complete!

Step 9: Progress on This Foundation

If you have completed this, then you have completed an amazing creative exercise and hopefully learned a thing or two about SVGs and Vue.js.

Now, there are a couple of ways you can move forward to sharpen your skills.

  1. Create more short stories: You can continue to create more short stories to practice your work with SVGs, writing, and overall creativity. You can also add more cool things like animations to really make something amazing. However, this is quite a lengthy process, but very beneficial, of course.
  2. Break down this exercise: What is awesome about making short stories with SVGs and Vue.js is that it really helps practice creating vector graphics and creative thinking which is really beneficial for frontend development. If doing entire short stories is too much, you can instead just focus on making vector graphics. You can do Coding Artist’s Daily SVG Images challenge to get prompts each weekday to have structured practice with vector graphics. On top of this, you can practice creativity by doing creative exercises at your own rate. I highly recommend The Imagineering Workbook which I referenced earlier. If you want to focus on breaking down Vue.js, I have a premium video course that does exactly that.

This is a very detailed post that took about 8 hours to write. If I missed something, you think this is cool, or you have any other feedback, all is appreciated.

Cheers,
Mike Mangialardi
Founder of Coding Artist

--

--