A free and open source, web-based online rhythm action game.
Started in 2015, it is built based on modern HTML5 technology and libraries such as React and Pixi.js.
The original name of the game was “beat☆music☆sequence”.
This name was derived from the file format that it uses,
.bms (Be-Music Source).
Later, I shortened the name to Bemuse, which happens to be a valid English word, meaning “to make confused”.
I built this game as a playground in applying software engineering principles and practices. It is also my graduation project. The project is open source, and has automated tests as well as a CI/CD pipeline around it.
The gameplay is heavily inspired and influenced by Lunatic Rave 2, beatmaniaIIDX, and O2Jam. It is key sounded, meaning that each individual note gets its own sound. The song will sound off if you did not hit the notes correctly.
I created this project because most PC rhythm games only work on Windows, and I use a Mac. I originally designed this project for desktops and iPads, but being web based, the game could be made to work on more devices as mobile devices become more powerful over time, bringing a truly cross platform experience.
In 2018, a 3D mode is added, and the game can be enjoyed in mobile phones.
Party mode lets multiple people play Bemuse together.
As of 2019, Bemuse has over 15,000 monthly active players.
# Software engineering
The first few weeks of development consists solely of setting up the project: webpack with loaders for Jade, SCSS, and 6to5 (now Babel). webpack-dev-server, JSHint, JSCS, Jasmine, Istanbul, Code Climate, Travis CI, among others.
Developing software in an Agile way entails taking to heart that “Working software is the primary measure of progress.” Within a month, I deployed a teaser page with a technical demo, which proves that a rhythm game can indeed be built with current browser technology.
Software engineering for me is about striking a healthy balance between building the right thing and building it right. Although I want to ship things fast, I want to do it on top of a sound foundation.
Here are some technical choices that I felt very happy about when I look back:
Setting up linting tools from the start with pre-commit hooks and an automated code review bot.
Using test-driven development for the game logic. As far as I remember, it never broke. Without the tests I wouldn’t dare replacing Ramda with Lodash in one go. You can even run the unit tests online. A Japanese player once reviewed the game and said that “beta 版だが結構安定している。” (although the game is in beta, it is quite stable).
Setting up the app to allow multiple entry points. This lets me create pages to test components in isolation before Storybook existed, and also keep the teaser page and as well as our unit tests online.
Not using too many webpack plugins. This made upgrading to newer versions of webpack relatively painless.
Not using ES features lower than stage 2 or custom Babel plugins. This gave a lot of interoperability with tools that were not based on Babel, and also eased the transition to TypeScript compiler later on.
Using clean architecture and separating the core logic away from UI frameworks and libraries. This allowed me to replace Vue.js (v0.11) with Ractive (v0.7) and subsequently replace Ractive with React (v0.13).
# Experiment with confidence and explore with safety
Clean architecture and tests enable me to experiment with new things. It lets me make many two-way door decisions. I can try out new (and perhaps not-so-mainstream) libraries and tools (such as webpack (at the time), Ramda, Ractive, and Bacon.js).
If they worked out well, then I could keep them (webpack being one example). Otherwise, if situation calls, I could switch to more boring, stable, tried-and-true solutions (such as Lodash, React, and Redux) at a relatively low cost.
For test runner I started with plain Mocha running in the browser. I created my own test runner script that fires up a browser, navigates to the test page, and then collects the test result. It then gets replaced with Karma once it has a perfect webpack support. I did not migrate to Jest because our tests required access to browser’s APIs such as canvas.
For continuous integration I initially used Travis CI. But since there are many CI services in the market, I commenced a CI war and also added CircleCI, AppVeyor and Codeship. In the end CircleCI wins.
For source code transpilation I initially used 6to5 which is later renamed to Babel. Getting tired of having to configure the plugins and presets and setting up regenerator, I replaced Babel with TypeScript compiler. One
tsconfig.jsonfile to rule ’em all!
For code coverage instrumentation I initially used Istanbul but its lack of ES6 support at the time made me switch to Isparta, which has some issues and that led me to create
babel-plugin-__coverage__for use in Bemuse. That Babel plugin later got incorporated into a new major version of Istanbul to which I migrated the project to once again.
Having a system for automated tests in place also allowed me to implement support for new file format in a single night.
Bemuse plays song files in Be-Music Source
.bms file format.
It is the same format used in Lunatic Rave 2 and others, and has a thriving community around it where ‘BMS artists’ collectively publish hundreds of original songs every year.
Most playable songs in the game, I reached out to BMS artists and asked for permission to use them in the game. Most artists are happy to allow me to use their songs for free, given that Bemuse is also a free game.
The background music for the game screens, as well as some playable songs, I composed myself.