virtex2 - v1.0.0

Cell Podium VITE TypeScript Project

This is a new typescript project template intended for VirtEx

  • Vite as bundler
  • Vitest for unit testing
  • Typedoc for documentation
  • Avoid "any" type, for example see how to cast json into a class with baseutil methods
  • Clean service for database access. The service should have no knowledge of the database json structure.

Files contain code for different purposes. Here are a few conventions

  • utils are files that have only or mostly static functions. Examples navbarUtils.ts with class NavbarUtils
  • services are files that contain classes that need to be instantiated. Examples are firebaseService.ts with class FirebaseService
  • models are files that contain strongly typed models reflecting the database. Examples are playerModel.ts with PlayerModel
  • handlers are files containing class that manipulate models. Example playerHandler.ts with class PlayerHandler
  • html are html files and can are clearly identified by their extensions
  • test are typescript files that do unit test for typescript classes (in particular handlers). Example playerHandler.test.ts

The folder structure should offer a "meaningfull" way to organize all files. One good rule for "meaningful" can be that a developer can find files without knowing berforehand where they are. Here are some guiding princles for this approach:

  • Keep related files close together Examples for related files can be:
    • The player model is only used in playerhandler; the files should be next to each other
    • The unit test for the playerhandler should be next to the the playerhandler
  • Keep utils and services at the closest folder where they are used
    • Servcices like firebase or s3 should be in a folder services
    • Utilities like baseUtils should be in a folder utils.
  • Angular like components Establish a habit of grouping angular like components together. An example is the placement component.
    • placement.ts is the typescript code for the component. It is invoked by the parent and the parent holds a handle to the component. The parent can supply a callback if necessary.
    • placement.html contains the html for this component. It is injected into the dom by the constructor of the placement.ts class.
    • placement.css contains any specific css for this component. It is injected by the placement.ts class.
  • index.html with index.ts (in src)
  • app.ts has the logic to administer the game

The application manages two types of players:

  1. Local Player:

    • Represents the player controlled by your keyboard inputs.
    • Only one local player exists per instance of the application.
  2. Remote Players:

    • Represent players instantiated and controlled by other users.
    • Multiple remote players can exist in the scene.
    • Visible and animated based on data synchronized from Firebase.

Both player types are rendered in the same scene and must be visible to all users for real-time interaction. However, only the local player responds to keyboard inputs.


The management of players is divided into the following classes:

  • BasePlayer:
    Contains shared functionality for all players, such as loading the 3D model (mesh) and extracting animation groups. It serves as the foundation for LocalPlayer and RemotePlayer.

  • LocalPlayer:
    Represents the player controlled by the user via keyboard input. This class extends BasePlayer and adds functionality for local input handling and movement.

  • RemotePlayer:
    Represents players controlled by other users. This class extends BasePlayer and updates its state based on real-time data received from Firebase.


Player data is synchronized between users using Firebase. To optimize performance, the data is divided into three types:

  1. PlayerStaticData:
    Contains information that rarely changes, such as:

    • Mesh file name (e.g., .glb file)
    • Player name
    • Role or other metadata

    This data is uploaded to Firebase when the player is instantiated and updated infrequently.

  2. PlayerDynamicData:
    Contains frequently updated data for real-time synchronization, such as:

    • Position (x, y, z)
    • Orientation (quaternion or Euler angles)
    • Current state (e.g., idle, walking, falling)
  3. PlayerLocalData:
    Stores data needed only locally, such as:

    • References to the 3D mesh
    • Animation groups (e.g., walking, idle)
    • Other runtime-only information that does not need to be synchronized with Firebase.

The class FBPlayerSync handles the synchronization of player data across all users via Firebase. Key responsibilities include:

  • Listening for updates to PlayerDynamicData and PlayerStaticData in the Firebase database.
  • Propagating local changes (e.g., player movement or state changes) to Firebase for real-time synchronization with other users.
  • Instantiating or updating RemotePlayer instances when new players join or update their data.

This structure ensures seamless integration of multiple players in a real-time 3D environment, leveraging Firebase for efficient data sharing while minimizing unnecessary network traffic.