SECRET OF CSS

Technical Insights After Building and Publishing My First 3 Web Games | by Joe Alves | Jul, 2022


An advice for designing games

1*sekZMn erjCvR Ag5wyQiw

As I’ve grown as a game developer over the last year, I’ve published three games that you can play right now in your browser:

  • Nov ’21: vast, a puzzle-platforming-programming game that mixes coding and 2D platforming gameplay.
  • May ’22: Download Speed, a racing rogue-lite in which you play a file being downloaded.
  • June ’22: Wake Up, Felix!, a reverse bullet-hell (think Vampire Survivors) starring Felix the Cat on top of a clock.

All of these games were made with the following priorities: learning and practicing game development, enhancing my portfolio, having fun/basking in creativity, and (maybe) winning some money.

My intention with this article is to brain-dump and share the technical details of each game (e.g. what tools and approaches I used) and insights into how and why I’m building games with JavaScript and the web.

1*Vo2LIi gQtf8SAAdZtM3Jw
Real first-person footage of a datum being downloaded off the internet.

I get this question frequently and I think it’s a good one. If there are tons of game creation platforms out there like Unity, Unreal Engine, Godot, etc., why am I building games with JavaScript outside of a robust engine?

First, I believe in the potential and upsides of web gaming. For example, many games made for the jams I’ve participated in require a user to download a .exe or .app file to run. This executable is typically not code-signed (i.e. you have to say “Yes, Windows/Mac/Linux, I am fine running this totally unknown and untrusted binary!”). That’s understandable for a non-commercial game product.

For me, my audience is already using the platform/process that my game will run in: the browser! All of my games are deployed to games marketplaces https://itch.io/ and https://gamejolt.com/ and playable right away without installation or downloading steps. This is also possible with approaches like Unity’s WebGL build output — but those approaches forego native control found writing for the browser first with JavaScript, like convenient and reliable access to Web APIs.

The low barrier of entry for players to engage with your game will always be browser gaming’s strongest feature.

Second, I love working with JavaScript. It is my expert language that I’ve practiced, built with, and taught to others for about a dozen years. Why would I not try to make games with it?

As the years go by and browsers improve their feature set and capabilities (e.g. WebGL 2.0, gamepad support, and other APIs), the idea of what a “typical web game” looks like is being challenged and I find that exciting.

Third, building games for the web extends my typical moneymaking skillset, you know … web development! If you are a web developer wondering if you can make games with JavaScript, I am writing this article for you!

1*dx6zENT mEpAgunB4wUaw
Felix the Cat surviving in the Stone Age.

In the above Felix the Cat .gif, the timer, health bar, and damage numbers are actually React components on a layer on top of the game <canvas>. I’ve employed this tactic with a front-end framework or just the DOM API to mix in traditional web elements that feel like they are a part of my game, but actually exist outside of it (or, on top of it).

Game development is essentially UI development, and I’ve carried over many things I’ve learned to my traditional business-oriented work.

3D visuals on the web are also becoming a hotter commodity for branding, marketing, and many other products and experiences. Working on my games teaches me things that are helping me build experiences that people will pay for!

My first web game:

A tireless mass of calculations.

I had made a few toy games before vast, but I decided to participate in Kajam 2021 game jam in order to build and publish my first fully playable game … however it turned out. I only had one week to do it!

The jam was run by replit who created the JavaScript game programming library Kaboom and encouraged participants to use it to build their game, so I did!

Choosing What To Build Your Web Game With

My choice for this game was easy (because it was selected for me), and I enjoyed working with Kaboom. But there are lots of options I could have selected (e.g. Phaser, Babylon, PlayCanvas, PixiJS, and more). Tool selection paralysis is a real productivity killer for otherwise prolific and creative coders. I feel for anyone stuck here; it is a bit of a trap. Here is how I think about, categorize, and strategize around this stuff:

  1. Understand that you are choosing a tool that will ultimately render visuals to a <canvas> element in HTML. I would highly recommend learning about the canvas element on its own and build some simple, controlled visualizations with it. When you’re making a game, you are essentially receiving player input and mixing it with visual content. The <canvas> element will always power the visualization of that content, unless you’re building your game with DOM elements only. Learn what it does!
  2. Notice the difference between a game “library” like Phaser, Kaboom, Babylon; a game “engine” like PlayCanvas; and a “rendering library” like Three.js. With a “game library”, your development will be non-visual/code-centric, but you will be equipped with lots of utilities and organizational tools that benefit most games like sprite animation and input modules. With an “engine”, you have a GUI where you can visually transform the objects in your game like you were using Photoshop. You’ll write code to attach to objects and sometimes other contexts. This is a popular way of building games evidenced by tools like Unity and Unreal Engine, due partially to their scalability and accessibility when you have a large team with disparate skill sets. With a “rendering library” like Three.js, you have abstractions to visualize content on your canvas and not much else, and very little that is oriented towards building games specifically. Strangely enough, I’ve built most of my games without a game library or engine, instead just this “rendering library”. I delve into the reasons why later.
  3. Know the visual capabilities/biases of your tool. Although they will all render to <canvas>, most libraries are built with either 2D graphics (e.g. Phaser, Kaboom) or 3D graphics (e.g. Babylon, PlayCanvas) in mind. Pick one that matches your vision!
  4. Recognize the needs of your scale. Clearly a lot of the advice and perspective in this article is from an individual developer making small games, not a large team creating a massive experience. Think about how collaborators will work with you on your product, especially artists and other coders. It’s always best to tailor your technical choices with scale and productivity in mind.

You can produce a great game in any tool I’ve mentioned so far. So, just pick one and MAKE SOMETHING! Learning one will carry over to another you may try in the future.

Kaboom was nice to work with and didn’t feel feature bloated, which I think is something that makes Phaser hard to use. Here is some example code from vast that shows a lot of different stuff at once:

Above code in the full game codebase.

That being said, I had to work around lacking control of certain mechanisms like controlling how gravity and platforms work. I talk about a lot of my challenges and process in this video devlog. There is one more thing I wanted to highlight before moving on: vast’s in-game programming interface.

1*gjsIs fZ KW9C3Dup2K HQ
You can put Modest Mouse references in your games if you want.

The primary way of playing vast is to write code that affects your environment. The execution of this arbitrary code that a player will write is achieved with eval which I would argue is an extremely rare use case for it. More importantly, the visualizing and editing of this code is not from Kaboom on the <canvas>, but instead a DOM element layered on top of the <canvas>. This also goes for the dialogue boxes that start appearing in level 7:

1*L3GlF9jL3rXZQ2Jm6L4kOQ

I emphasize the usage of DOM elements (and by extension any front-end frameworks like React, Vue, Angular, etc.) in my games because they suggest powerful control and visual freedom in your game UIs, as well the usage of interesting elements like <video> (e.g. webcam stream). And you might already know this stuff! If you’re a web developer reading this, I hope recognizing this seems empowering and full of possibilities!

My work on vast brought confidence that I can make a game I am proud of with tools and platforms I already know well. I consider vast to be my most personal game so far— the idea for it springing out of my day-to-day programming andragogy, and the horror themes inspired by my own nightmares. It has a limited player base (requiring programming knowledge to play) but I’ve received great feedback on it from those who have played. Thank you if you are one of them!

If you need hints on completing vast, feel free to contact me! The game isn’t over until you’ve beaten the final boss.

I was excited to do another game jam and build something else … eventually. Half a year later, I found the time and made my next game:

1*PCigf4ywbDZbufUCBkBZ1w
Quickly! The user is waiting!

Download Speed is (I guess) a racing game, stylized around the idea that you are a file making its way from origin server to user computer — with only 2 minutes to do it! It renders through Three.js, and the entire UI and HUD is built with DOM elements, including our friend Blippy!:

1*a3Q9Iy8H0h G aU50WVyPg

It was made for a casual game jam with the theme “Time is Money” and a required special object “Clip”. One of my favorite things about doing jams is working under the constraints of their themes. In Download Speed’s case, “Time is Money” prevails in the game’s upgrade system/economy in which you have to spend remaining time to get faster. “Clip” hopefully is obvious, and including a character like Blippy really drove the file download lore in the first place!

As I said, I made the game with Three.js, which is not at all a “game library”, but more of a “rendering library”. Let’s explore that:

Three.js Basics in Brief

Three.js is a library that abstracts built-in browser WebGL methods to allow you to conveniently render a 3D scene to a <canvas>. A 3D scene is made up of the world space, the objects within (which include shapes, models, lights, etc.), and at least one camera viewing the space/scene. You have access to a mechanism that renders an image (usually called a “frame”) of that space and transformations of the objects or the camera in that space will be reflected in subsequent images. The Three.js library also comes with utilities to calculate things within the world space like linear algebra functions and constructs, but not much in the realm of “game making” utilities.

Three.js is not a library for making games specifically. A lot of people run into this truth early when looking for basic game functionality like listening for user input, detecting collisions, or controlling the camera in a typical way. I built a first-person character module to use in Three.js, because it has none:

1*fksWXGhha8wW TBNsn7I2g
Moving a FPS character camera around a sandbox.

Download Speed never ended up having this freedom of movement, but did evolve from my work in implementing a first-person perspective character controller in Three.js — seen above. This character can move, look around, jump and fall, walk up slopes and slide down steep slopes, and interact with objects at a configurable distance (like shooting a gun).

I implemented this controller from scratch with mathematical concepts that I have been studying for about a year. I used a gutted version of it for Download Speed, and am using it to drive the gameplay in a larger, work-in-progress game.

Although this takes extra effort beyond using a built-in controller in a game library or engine, working at a low-level with Three.js gives me control and flexibility to create systems that I can adapt at a fundamental level, which leads to more unique gameplay experiences.

“So, do I have to do math to make games?”

You don’t, and you can absolutely build great games without learning a ton of math. However, you do achieve a level of expressive freedom and easier debugging if you establish a strong foundation in linear algebra. Here is what comes up as useful for me very often and I recommend that you eventually study, too, if you’re serious about game development:

  • Understanding vectors and how to operate on them. This includes vector addition, subtraction, multiplying by a scalar, and dot product. Thinking in vectors helps in both 2D and 3D spaces to get your objects interacting with each other and moving the way you want them to. Vectors are how you describe position and orientation in a world space, like calculating the direction and distance between your player and an enemy, or if they are looking at each other. Learn them well, from multiple sources!
  • The nature of the sine and cosine functions. I have to shout out this article for helping me understand how these functions can be used to generate a cycling value which I have used a ton in my work since. Simply combining a timestamp (e.g. from Date.now) with a Math.sin/cos is enough to do wildly awesome stuff.
  • Nested world spaces and applying matrices. Do not sweat all of the matrix operations details and instead work on conceptualizing how coordinate spaces exist in a hierarchy, and how matrices can be used to apply transformations from one coordinate space to its parent, and vice versa. This is very related to using Group in Three.js and can save a lot of headaches when debugging those.

This chapter of “3D Math Primer for Graphics and Game Development” really helped me with this concept; the book is a solid though challenging study in general. I learned about the maths I need while learning other things but I’d estimate I’ve been focused on it for six months so far.

On Learning Math

I understand the hesitancy to learn math; I honestly hated math in school. You’ll be glad to hear that math feels applicable in virtual spaces like making 3D scenes, immediately answering the classic question of “What would I use this for?”. My process for learning what I needed to know was to encounter the problem, or desire for a specific effect, then learn the math to solve that problem or achieve that effect.

I want to reiterate advice to learn math from multiple sources. Math can really feel like alien magics until the correct person has explained it to you for the 5th time, possibly in the best way your brain thinks.

I think that the strongest line through math and coding I have found is the “conceptualize-to-apply” nature of their constructs. Math.cos is akin to using a for loop, in the way that you need to first strongly conceptualize what they do independently, discover practical usages for them, and then practice them while solving different problems.

Learning this type of stuff is optimized by different perspectives, because we all think differently from one another, and communicate ideas in very nuanced ways. Here are some resources that helped me a lot, for your variety:

Code + Gifs For Your Perusal

Here are screenshots of code with in-game footage:

1*ztPwGeUs4mO51f pczPTgA
Blippy says, “Get faster by picking up speed fruit!”

A speed fruit is a round-shaped mesh, given a material color and radius (size). It’s added to a group that will be appended to the scene elsewhere. Source code.

1*BLleJ6BTojxT0r2kp 5mig

All of Blippy’s famous quotes.

1*sekZMn erjCvR Ag5wyQiw
Blippy says, “Yes! Faster!!!”

Usage of post-processing shader passes with the Three.js renderer to enhance the feel of the game. Source.

Giving your Game “Juice”

If two games play exactly the same (think about how many 2D platformers are out there), but one feels FUN and the other feels dull, it’s probably got a lot to do with “juicing”. Juicing is a term that game developers use to describe the usage of sound, visuals, vibration, and other stuff to enhance the “punchiness” of a game — the often unrecognized but subconsciously felt polish that players need and expect from games that are satisfying to play.

If you’re playing an action-packed first-person shooter like Doom or Call of Duty, and you are struck by an enemy (or their weapon) … what do you expect should happen? I encourage you to take a second and envision you are playing this game, or building it, and think about all the things that might happen because of this moment of your character being struck.

Some things I thought of: a flash of red screen, a hit sound (maybe a robust “argh!”), a blurry screen (especially if struck by an explosive), a brightening/darkening of a health meter to describe lost health, a rattling of the camera or controller vibration. What else have you seen before?

Now imagine playing a game like this, getting hit by an enemy bullet or fireball, and having … none … of these happen. Not only does that game feel less fun, it is also more confusing and frustrating to play.

Did I just get hit? By what?!

It was really important for me that Download Speed felt fun to play, being such a short and hopefully intense experience. I wanted the player to feel the difference between slow and fast. I wanted players to grab speed fruit not only to become faster, but because it was satisfying to get them. I wanted an experience that builds in intensity from beginning to end.

Here are a few ways I tried to “juice” Download Speed, with some implementation details:

When a player grabs a speed fruit

  • The screen flashes green or pink depending on the color of the fruit. This is done with a post-processing renderer shader program with a color uniform.
  • A strong boost of speed glides them forward. This is a degrading scalar applied to the user’s base speed vector. This is also simply a base mechanic of the game (Blippy calls it a “boost”) to encourage players to chain fruit pick-ups together.
  • A pick-up sound plays, lower-pitched and quieter for normal fruits, high-pitched and louder for super berries (the pink orbs).
  • A blur level based on the user’s current speed. This effect is way more obvious at high speeds, and is implemented with a GLSL post-processing shader on the renderer.

GLSL Shaders

Shader programs are available in most renderers (e.g. like the ones used by Unity and Blender) and they are a way of informing the GPU how a material or image should render.

I found learning how these shaders work to be so far indispensable in producing interesting visuals in my games, and solving some really hard problems (like the texture issue in Wake Up, Felix!, later in this article).

This is a pretty involved concept and this article is long, so I will simply demonstrate and share some stuff and move on:

  • “Learn GLSL Shaders from Scratch” by Nicholas Lever on Udemy. This course was extremely informative but difficult. I recommend it highly if you love to experiment and be challenged in your learning.
  • The Book of Shaders is an unfinished classic and something I reference occasionally.
  • My Shader CodePens, which includes demos from the above resources that I recreated or forked, and my own experiments. I go back to these to implement visuals in my games often.

And here is how I used shaders in to enhance visuals in Download Speed:

1*W1Tq1iCiQkOFFps nuaLqA

The floor

1*5PV4Yd1g6bHl7DQeNZeglg

Blur and flash, and final goal.

Sometimes jams have huge cash prizes ($25,000!), so right after I finished Download Speed, I worked on:

1*ORE1YuJW2Emu94y4v Sybg

Wake Up, Felix! was made for Together Jam 2022, sponsored by NBC Universal. I was allowed to use Felix the Cat, and the theme was “Power in Numbers”. I’m proud of how I matched the theme for this game: you are offered a new weapon every minute, for the matching number on the clock.

1*appZu8EslM3pl7aOl BKvw
Weapons 5, 6, 7 and 8

This game, like Download Speed, was made with Three.js which may immediately seem weird since the game feels mostly 2D. The 2D sprites are actually textured materials rendered to Plane geometries, and are moved around in a 3D scene. You can sense that the camera rotates to show this mix of 3D and 2D, and there are usages of lighting on the clock and weapons to accentuate the mixed perspective.

Here is the camera rotation massively exaggerated on a local copy of the game, to show an extreme version of this visual effect:

1*Me9191GBPJSKeTbpmmw2vA
You’d get pretty seasick if the game was like this!

I was inspired to make a game like Vampire Survivors because I thought it would be an appropriate experience to have scores and leaderboard, which was another requirement of the jam. The leaderboard also includes which weapons you chose!

2 is a pretty popular weapon. #TeamHammer

One of the most important things for me with this game is that I could put TONS of enemies on the clock, especially near the end of a run. I ran into performance issues early on that slowed the game down when I tried to spawn even 10–15 enemies at once.

Three.js’s Texture First-Time Render

As mentioned earlier, the 2D sprites in this game are in fact 3D meshes with plane geometries and a material rendered on one side. At first, this material was a MeshBasicMaterial with a texture map.

When a texture is first used for a material, there is a “first-time render” step that Three.js takes to calculate and cache information about how to render the texture. This applies to every texture in your scene, even if it is the same kind of texture you’ve already used (e.g. the mammoth sprite). What that meant for me is that every enemy would stutter the game on spawn, and it played awfully.

My first attempt to solve this issue is to share the same texture for every enemy across all spawns of the same enemy. This solved performance issues but didn’t work because if I flipped the texture (to turn the enemy around), or changed its offset (to animate the sprite), it would apply that transformation to EVERY enemy of that type on the screen. Pretty awkward.

I finally solved the problem … with a shader!

This shader receives the same loaded texture for the same enemy, but allows for independent control on a single mesh. This shader plays the animation, flips the texture when needed, and even handles the “hit flash” when enemies get hit.

I am proud of this code, as I feel my ability to write it came as a culmination of learning and practice I had been grinding on for months. And, it solved a major problem in my game!

Now I can have TONS of enemies, see?:

1*HvX3bWWbrwYdFMEDAjJldA

Game Art

All the 2D art in the game was drawn by my good friend Hunter, and all the music/sound by my partner Elissa!

1*a8qJVSp7R6zF4YW3Det5Bg
Mammoth enemy.
1*iiYYw19cBnWRwVZyX9uP0Q
Felix walking.
1*PBdEMNFqcyHb2o863BFUig
My favorite enemy, Tuba Guy!

I also used this jam to stretch my own artistic skills by making all the 3D models in Blender!

Weapon IX (9).
0*KHtrWgaXNtA3pKZN
Weapon XI (11).
All weapons and clock numbers are in the same file. Seeing it all mashed together like this must be some kind of phobia!

I appreciate you reading this article and playing my games. Making these products takes tons of effort in order to learn new skills, build in efficient ways, and fulfill a creative vision. Every play of any of my games is cherished. ❤

I hope that this article introduced you to interesting concepts, tools, and thoughts.

Some Parting Advice for Aspiring Web Game Developers

  • Start with 3D fundamentals first. Using a program like Blender is a great way to start. Build your own understanding of 3D world space, geometries (vertices/edges/faces), position, scale, rotation, materials, etc.. Every concept you may encounter in Unity, Unreal Engine, Three.js, or another 3D platform will likely be found in Blender, where you can toy around with it, and press “Undo” a bunch.
  • Participate in a game jam. Game jams are highly motivating for me and a great way to learn from others. It is also useful to work at a small scope especially if you want to practice building and actually finish projects. If you want to collaborate on a jam with me in the future, please reach out to me! I am open to working with others, even if you have limited experience.
  • Get out of tool selection paralysis and just make. This is important advice for any programmers making anything, but tooling doesn’t usually matter as much as your concerted efforts. The best things to look for are documentation, community, and available examples.
  • Harness the web! I have other, long-term games in the pipeline that use Chrome Extensions as part of their gameplay, and WebRTC video streaming! As I mentioned earlier in the article, I think the browser’s potential for unique gaming experiences is massively unexplored. Others may convince you, a web developer, that you have to switch your platform to make a compelling game. YOU DON’T!

Thanks for reading!



News Credit

%d bloggers like this: