Posts

Custom Cursor Images

🏆️ This is a sponsor-only post, if you're seeing it, that means you are amazing and thanks to your support Monogatari keeps getting better every day, thanks a lot! Please don't share or distribute the contents of this post, usage in your game is of course permitted though!

Another video happened! Got some things fixed and some new challenges such as going off topic a bit and I haven't nailed the right volume for my microphone yet but thankfully it seems like the automatic captions from youtube are doing a great job at deciphering my voice so they're actually not bad subs. All in all, I think it's getting a bit better! Third time's the charm (I hope!)

This time, we went over something we all may have missed and that is the usage of custom cursors for your visual novels. This is actually something pretty common to see on VNs so not sure how come we had never talked about it before.

You can go ahead and watch the video here: Monogatari - Custom Cursors - YouTube

Samples

Want to see how it looks? Here are some samples:

Creating Your Cursors

Custom cursors have a few limitations that are important to remember:

  1. Your image should have a size of at most 32x32 pixels. At this size, chances are you won't be able to show too much details so don't make anything overcomplicated.

  2. It can't be animated, even if you use a GIF or APNG files, the cursor will not be animated

  3. It can have transparency

  4. It's recommended to use either a PNG or SVG format

Depending on your novel, you might want to have different styles for your cursor but the basic ones you should probably have are:

  1. The "idle" or default style: This will be the default image for your cursor

  2. The "hover" style: This will be the cursor that will be shown whenever the user hovers a button or some other element with which it can interact

  3. The "active" style: This will be the cursor that will be shown when the user clicks

For the purposes of this tutorial, I'll use these names for these three states:

cursor.png
cursor_hover.png
cursor_active.png

Adding it to your game

Once you've created your cursors, you should copy them to the assets/ui directory. This directory is the place where you should put all the images that are related to the user interface such as image buttons, text box backgrounds, main menu covers etc.

Once you've added your files into your project, all we need to do next is edit our main.css file to let our browser know what we want to use as a cursor.

Adding the default style

To set our default or idle cursor, we'll set the cursor CSS property for our body tag. That means this will apply to all the page.

body {
    cursor: url(./../assets/ui/cursor.png), auto;
}

That's it! All CSS needs to know is where's our image. Notice we also provided another value: auto. All cursor properties need a fall-back in case the browser is unable to show our custom one. auto tells the browser to just do what it normally does, so shows an arrow-like icon for the normal cursor, a hand-like one when hovering a button etc.

Now, this is cool and all but if you test your game as it is, you'll notice the custom cursor you added is not actually being set for all the page as we thought. There are certain elements that will enforce other cursors, for example the buttons in the main menu will show the hand-like cursor. The reason for this is that some elements already have a CSS cursor property set and thus, we need to overwrite it. The devtools of your browser are your best friend in the task of finding out how to overwrite those styles.

Adding the hover style

Let's take a look at those main menu buttons. We probably want to show our hover styled cursor when the user's cursor goes over a button so we'll need to find out what style we need to override.

If you inspect one of those buttons, you may be able to find this CSS rule is being applied to them:

[data-action] {
    cursor: pointer;
}

pointer is actually the name of that hand-like cursor so, now we know why that's being shown even after we set a cursor for the whole body.

Now, what we want to do is to show our hover cursor when the user hovers over a button and CSS has the perfect thing for that. Buttons have a [:hover pseudoclass](Pseudo-classes - CSS: Cascading Style Sheets | MDN) that let's us set a custom style for exactly that situation, convenient!

Let's go ahead and do:

button:hover {
    cursor: url(./../assets/ui/cursor_hover.png), auto;
}

But! If you do it, you may notice it's actually not working, the pointer is still being shown.

The reason for that is specificity. Remember CSS stands for Cascading Style Sheet as a reference to its behaviour to act like a cascade, where the last style overwrites the previous ones. However, it also takes the selector specificity into consideration when deciding whether a style should overwrite another one.

Let's see an example:

button.primary {
    color: red;
}

button {
    color: blue
}

In this code, the last style we have for buttons says the color for them should be blue, however, the button.primary selector has more specificity since it refers to a button that also has the primary class.

So, for buttons with that class, the style won't get overridden and they will retain their red color.

Now, let's get back to our main menu buttons case. The [data-action] selector is actually more specific than our button selector so, our style is not able to override the other one. Fixing this is quite simple then, we only have to use a selector that is equally or more specific.

button[data-action]:hover {
    cursor: url(./../assets/ui/cursor_hover.png), auto;
}

This time, we should be able to see our hover cursor when going over the buttons. You may however notice a small glitch, if the mouse is not over the button, then you slowly bring it over it, you'll see we get three cursor icon changes, it goes from idle to pointer to hover when we actually expected just to see idle -> hover.

The reason for this is the fact we're using the button's hover pseudo class and it actually makes sense, the button by itself does not automatically goes from idle to hover, there's a small delay before that happens and that delay is what's causing our style not to kick in immediately.

To fix this, let's add another selector to our rule:

button[data-action],
button[data-action]:hover {
    cursor: url(./../assets/ui/cursor_hover.png), auto;
}

This time, we're saying we want the buttons to have our hover cursor by default and when you think about it, it actually makes sense, when I'm on a button, I'm already hovering over it so it doesn't make much sense to have two separate rules for that.

If you test your game again, the glitch should be gone.

Adding the active style

Finally, we want to add our active cursor when the user clicks on a button and the process is pretty much the same as for our hover one. Buttons also have an :active pseudoclass so our style is simply:

button[data-action]:active {
    cursor: url(./../assets/ui/cursor_active.png), auto;
}

So now, your button should go directly from idle to hover when you put your mouse over it and then change to active whenever you click on it. Awesome!

Cursor Coordinates

We've managed to add our custom cursors but there's one important task left and that is correctly indicating what's the "active area" of our cursor image.

The active area refers pretty much to what's the point of your cursor that's actually making the click, is it the upper left corner as with the arrow-like cursor? Is it the center? Of course, this depends completely on the image you created.

For my cursor images, the active area is actually the center and CSS lets us tell our browser that just by specifying our coordinates. These coordinates are an x-y system that starts at our upper left corner and should have values between (0, 0) and (31, 31).

So, what's the center of that? Well, the center is probably somewhere between (15, 15) and (16, 16) so... let's go with 15, 15. Providing these coordinates to the browser is simple, we just need to add them to our cursor property:

body {
    cursor: url(./../assets/ui/cursor.png) 15 15, auto;
}

Notice however that if you now test again your cursors, you'll notice when it goes from idle to hover another glitch may ocurr, this time causing the cursor to kind of teleport to another position when it changes and the reason for that is you need to provide these new coordinates to all of the cursor properties we just added so:

body {
    cursor: url(./../assets/ui/cursor.png) 15 15, auto;
}

button[data-action],
button[data-action]:hover {
    cursor: url(./../assets/ui/cursor_hover.png) 15 15, auto;
}

button[data-action]:active {
    cursor: url(./../assets/ui/cursor_active.png) 15 15, auto;
}

This way, we won't have that glitch any more and this actually tells you something else, you should be consistent in your cursor images to avoid this. The reason we were able to set the same coordinates for all these images is because I made all my images visually have the middle as the important part. If you create completely different images for each state, chances are they will require different coordinates and that will cause the glitch to happen which is not really nice.

Using different cursors for different elements

Another cool usage we may have is using different cursors for other elements such as choices. We could for instance let the users know which choice represents something good and which one something bad just by changing the cursor they get when hovered, as an instant feedback before they actually have to press it.

As it's common with monogatari, using CSS classes is the way to go here, remember choices can actually have custom classes, for instance:

{
	'Choice': {
		'Dialog': 'y Have you already read some documentation?',
		'Yes': {
			'Text': 'Yes',
			'Do': 'jump Yes',
			'Class': 'positive'
		},
		'No': {
			'Text': 'No',
			'Do': 'jump No',
			'Class': 'negative'
		}
	}
}

This statement will add the positive class to the Yes button and the negative class to the No button.

We then, can use the following CSS code to make it have different cursors for each:

button.positive {
	cursor: url(./../assets/ui/cursor.png) 16 16, auto;
}

button.negative {
	cursor: url(./../assets/ui/cursor_active.png) 16 16, auto;
}

So, you can really set custom cursors to pretty much anything, even a different cursor for every character.

And that's it for this tutorial! Hope you find it useful and as always, thank you so much for your support!