How to combine your two favourite things to make an exciting and engaging experience for your users.
Growing up, I spent my spare time doing what most programmers did; played video games every waking moment. I loved Adventure games and what a time sink they were; if time was the Mary Rose, and I was the French, my artillery were games like Kingdom Hearts, Ōkami, and Borderlands.
Why did I, and others, spend so much of our spare time exploring, surviving, dying, and (so, so much)grinding? Hundreds of factors contribute toward making an engaging experience, but the one I'm going to focus on is the notion of progression.
The idea of gamnification isn't new, with many popular applications (like todoist, or challenge timer) incorporating some sort of progression scheme to make us, the consumer, use their app, give them money, and hand over our personal data. So I decided to go about my way of enabling others to do just that, through beautiful skill trees! Note: I expect neither money nor data from those using my personal skill trees.
The last few weeks have seen me toil away to create what I hope to be a pleasant plug'n'play React package to help you create exciting skill trees. You can test it yourself by following the tutorial. I hope it to be a frictionless experience.
We hope to have something resembling the skill tree below.
https://thepracticaldev.s3.amazonaws.com/i/sn9tgrqpv98tm4ftqvqx.png
Grab the starter repo by using git clone git@github.com:andrico1234/borderlands-skill-tree.git
Move into the directory and run the starting script, yarn start
. Give the site a whirl, you'll see nothing but the Borderlands logo and environment.
beautiful-skill-tree
exposes three components: the SkillProvider
, SkillTreeGroup
, and the SkillTree
components.
SkillProvider
: This takes in no props and supplies the children with the skill tree's context. This puppy handles all of the global data related to the skill tree.
SkillTreeGroup
: Is more involved in that it can take an optional theme
property, where we can pass in some custom styling, to make our skill tree feel very Borderlands. The SkillTreeGroup
also uses the children-as-a-function pattern to give us access to some imperative api functionality, such as skill tree reset, selected skills counter, etc. We don't need to worry about any of those for the scope of this article.
SkillTree
: This is the most exciting of the package's exports, unless you're a sucker for typings (which are also exported, for all you TS fans). The SkillTree
doesn't take any children but requires 3 props: treeId
, title
, and data
. The treeId
should be an id that's unique to each skill tree, but should be persistent across user sessions as this is used as the key for getting and setting the data to local storage. I'm not going to explain what the title
prop does, I'll leave you to experiment. The data
is the mixing pot of the application. You'll pass in your skill tree data structure which the app will use to render a beautiful-skill-tree
. Let's get a real basic tree going before we move on to our multi-tree, multi-branch Borderlands spectacular.
In App.tsx, import the 3 components like so:
import { SkillProvider, SkillTreeGroup, SkillTree } from 'beautiful-skill-tree';
Place it underneath your img
tag, outside of the image's container div, but within the outer div. Add the SkillProvider
, passing the SkillTreeGroup
as a child. Before you do the same with the SkillTree
, remember that as SkillTreeGroup
uses function-as-a-child pattern, you'll need to render a function that returns the child components. Return a single SkillTree
and give it a treeId
and a title
prop. Pass an empty array into the data
prop so your App.tsx
looks like this.
function App() {
return (
// <div>
// <div headercontent />
<SkillProvider>
<SkillTreeGroup>
{() => {
return (
<SkillTree treeId="basic-birch" title="First Skill Tree" data={[]} />
)
}}
</SkillTreeGroup>
</SkillProvider>
// </div>
);
}
Go to localhost:3000 to see the application running. You should see the logo, background, and a grey rectangle. If you're running into any errors, go through the introduction again and check to see if there any syntax error or incorrect imports.
Next, let's create a real basic tree. Just 3 items that move in a linear line. The data structure for data
looks like this:
type Skill = {
id: string;
icon?: string;
title: string;
tooltip: {
description : string;
},
children: Skill[];
}
Each skill requires four properties, with one being optional. You should also notice that the children
property is a recursive type, meaning that it takes an array of the same data structure, which it uses to render the children of the skill. This can go on infinitely, and make for some real complicated, winding trees. I'll create the first skill for you, and I'll trust you with carrying on for the next two items.
const data = [
{
id: 'first-skill',
title: 'The root node',
tooltip: {
description : "The parent node, all of the descendants will be locked until it's selected",
}
children: [
// rinse and repeat; always repeat.
]
}
Add the above snippet to the App.tsx
file, and replace the empty array inside of the SkillTree
's data
property with our data
definition. Load your page, and you should have an interactive node. Give it a hover and a click and it should be reacting to your actions. If things are working, then I'll task you with creating two (or more) child nodes. Experiment with children and sibling lengths, to see what you can come up with. (If you also happen to break my precious package, leave me a GitHub issue so I can patch things up).
Once you're comfortable with creating a skill tree, let's go ahead and create our Borderlands skill tree. Fortunately, I've done all of the tedious work for you and have already created the data structures and accumulated the images.
You'll need to import the three trees from the data
file, which can be done via
import { motion, harmony, cataclysm } from "./data/data";
The next step is creating two additional SkillTrees
alongside the current one. You'll need to wrap them in a React.Fragment
as your SkillTreeGroup
will now be trying to render 3 top level components. Pass in the data accordingly, and if you're unsure, I've posted the code snippet below.
<React.Fragment>
<SkillTree treeId="motion" title="Motion" data={motion} />
<SkillTree treeId="harmony" title="Harmony" data={harmony} />
<SkillTree treeId="cataclysm" title="Cataclysm" data={cataclysm} />
</React.Fragment>
Go ahead and check your web browser, it should be aaallmoost ready. We've got the skills rendered, but the styling feels a little lackluster. It doesn't feel very Borderlands. Fortunately for you, I'm a regular Neil Buchanan and prepared a custom theme. Import the theme and pass it through to the SkillTreeGroup
's theme
prop. The theme object is export via import theme from './data/theme';
. Easy!
https://thepracticaldev.s3.amazonaws.com/i/efhb04w09pc44j8z44dr.png
Once you've done the above, check out the finished product. If you're still not satisfied with the styles, check out the theme object and customise it yourself, there are a bunch of additional attributes whose styles can be adjusted, so just peek into the typings of the package.
I mentioned earlier that there are a few additional properties and values that can be used to tweak the skill tree, so have a mess around yourself, and link me to any cool trees you create. I'd love to add it to the growing list of trees found here. Here's an example of the skill tree that kickstarted this obsession.
I hope you've enjoyed tinkering with the beautiful-skill-tree
package. I'm always adding new features and updating, so give it a star on github! You can find an online demo of the borderlands skill tree here
You can find me on Instagram or GitHub if you want to chat code, music or fitness!
Top comments (0)