Organising a Casino Slot Client Application

Developing casino slot games can be a challenging endeavour, particularly for those who are new to the field and lack in-depth knowledge of the domain. A common initial approach is to design numerous shared components with the intention of reusing them across various slot games. However, this strategy often proves to be a misstep.

In the current landscape, slot games are highly diverse, with each game featuring its own unique narrative. This includes distinct bonus games, animations, and an overall unique ambiance. As such, a one-size-fits-all approach to component design does not effectively cater to the customised nature of modern slot games.

Our experience taught us a valuable lesson. Initially, our goal was to maximize reusability, and we envisioned a back-office application that could function as a slot game builder. To this end, we developed shared components such as reels, symbols, and win grading systems, intending them for use across all games.

However, we soon found ourselves trapped in this approach for over a year. We were constrained by the limitations of the anticipated slot builder, and each modification for an individual game, like introducing a collect feature, necessitated changes to the shared reels component. This had a ripple effect, requiring our QA team to retest every game due to their shared codebase. The prospect of implementing game-specific custom animations was hindered too, as any new animation needed to be incorporated into the shared component, and we had to ensure it didn’t disrupt other slots. This approach significantly limited our flexibility and creativity in game development.

Additionally, it’s important to consider that each game must undergo certification in regulated markets. Therefore, updating the game’s visuals post-certification is not a viable option. This factor further complicates the process and underscores the need for developing games in isolation. The objective is to design a game, thoroughly test it, and then move on to the next project. If we conceive a new feature for an existing game, the approach is to develop a sequel incorporating that new feature, rather than revising the original game.

Drawing from these experiences, we are now equipped to formulate a development guide for our future slot games, as well as for other casino games.

Technology

Casino games can be created using frameworks such as Construct or Godot. However, the most widely used and arguably the industry standard for developing these games is the PixiJS library. Alongside Pixi.js, incorporating the GSAP animation library and RxJS for reactivity can enhance the development process. Additionally, employing a build tool like Vite or Webpack is essential for efficient game development. For more design controlled animations, Spine can be used.

Games can be structured using individual repositories with a shared library included in each. However, as I strongly support the use of monorepos for frontend development, my preference is to organise all games within a single repository. This approach streamlines the development process.

Frameworks and versioning

WebGL development is advancing swiftly, leading to an improved and faster gaming experience in browsers. With the introduction of WebGPU support in version 8, PixiJS significantly boosts rendering and animation speeds. This rapid progress underscores the importance of staying current with these frameworks. However, given our primary focus on developing a game and then moving on, we must devise a strategy that allows us to utilize updated library versions for new games without retrofitting older ones with the new framework. This approach ensures we only revisit previous games when absolutely essential, thereby streamlining our development process.

Since NPM supports package aliases now we can install multiple versions of library and use it where required.

            
"dependencies": {
    "pixi7": "npm:pixi.js@7.4.0",
    "pixi8": "npm:pixi.js@8.0.0-rc.6"
}
            
          

With the ability to use Pixi8 for new games, we can innovate and experiment without the risk of disrupting older games that are built on Pixi7. This flexibility also allows us to explore the capabilities of the library within the same project, enhancing our development process while maintaining the stability of existing games. Same is true for every other library.

Structure

In this directory structure, we have established shared components which are essentially elements that rarely change. If a specific game requires a unique variation, we inherit from the shared component and customise it to fit our specific needs. Shared components ought to be designed without any game-specific information and should be highly parametrised to ensure maximum flexibility while maintaining backward compatibility.

As we can see in the example, game AztecEmpire extends some of the shared components. Each game features an index.js entry point, which bundlers utilise to compile the distribution specific to that game. Adjacent to the index.js file, we have the option to include an index.html file. This serves as the HTML page into which the compiled code will be injected, offering an alternative to using a singular public/index.html page.

Composition

Rearranging components into different containers within a PixiJS application can be challenging, emphasizing the need for careful planning of component composition within the main container, which is established in the Game.js component of a game. It is advisable to avoid additional nesting of components; instead, all major components should be directly included within the main game component. This way we can also avoid using layers in PixiJS.

In this simplified graphics we can see the composition of a main elements of one slot game.

  • Background: This element, typically an image, spine animation, or even a video asset, forms the game’s backdrop. The asset can vary based on the game’s state, such as during base or bonus rounds.
  • Reels: A crucial component containing symbols, symbol movements, payline animations, and more.
  • Reels Masks: This component includes masks applied to the reels, usually a set of texture assets that change according to the game’s state.
  • Additional Features: This encompasses various extra slot game features, such as progress bars, bonus collects, jackpots, and so on.
  • Current Spin Info: Positioned usually below the reels, it displays the current win amount from paylines and any collected cash symbols.
  • Game Logo: Located above the reels, this component is sometimes integrated into the background, making it optional.
  • UI Elements: All user interface components, including the spin button, autoplay button, menu info button, jackpot details, etc.
  • Win Grading: A display that activates when a player achieves a win exceeding a certain threshold, categorising the win as “big,” “ultra,” “sensational,” and so forth.
  • Total Win Amount: This component shows the animated total win amount, counting up from zero to the win. It’s layered over the win grading to eliminate the need for cloning or moving the component to a different parent when the win surpasses the grading limit, allowing for a seamless transition in displaying the win increase.
  • Dialogs: Various pop-ups, such as information about the start of free rounds, promotional announcements, jackpot victories, dialogs from autoplay, menu, etc.
  • Intro: Component that is shown before start of the game. It serves to on-board player to the game and also to force player to interact with our game so we can turn on audio.

Naturally, there may also be supplementary components designed to display animated characters interacting with the reels or performing similar actions.

Typically, spanning across the entire game, we employ a shared loader that is responsible for loading game assets. It displays a progress bar to indicate the loading status and initialises the game before it eventually conceals itself.

API

Given that the backend typically serves all games but provides different responses based on the specific game or game type, it is beneficial to have dedicated parsers for each game or game type. Whenever we receive a response for actions such as a spin, bonus buy, or cash-out, it’s crucial to parse this data into a format that aligns with our game’s requirements. This parsed data is then stored within the application and utilized throughout the duration of a player’s session.

Build and Deploy

Operating with a monorepo necessitates a dynamic build command that varies based on the entry point, specifically the index file within each game. This setup allows for the flexibility to build either a single game or multiple games simultaneously. When deploying on static site cloud providers like Netlify, Cloudflare, or Vercel, we can opt for separate subdomains for each game. Alternatively, deploying everything under a single domain and differentiating games via URL slugs is another viable strategy. However, this latter approach can complicate the deployment process in a monorepo environment with static site cloud provider as a host.