7 minutes
Data-Driven Game Worlds
In this series, we're diving into building a game framework using a simple yet performant, Entity Component System architecture. This way of setting up your Babylon.js game is optional, and there are many ways to build a game. One of my core goals is to possibly run many games off the same code, using different data as inputs. Data which will define everything from the locations of downloaded assets (Like Meshes, Textures and Sounds) to defining options for how the controller maps to player movement.
Many traditional game engines tightly couple game logic and data directly within the code. While this can work for smaller projects, separating your game's data from its code offers significant advantages as your game grows in complexity.

Project Setup
Add Our Directory Structure
Open your terminal in your project's root directory and run these commands to create some folders and files we'll use.:
This creates the following directory structure:
We'll be using these files and folders throughout the course, but quickly, in your project root directory, you should have a public folder, where the compliles game data will live in GameData.
The data itself is typescript files, because as we'll see it makes building games more flexible than using plain JSON. The scripts folder will hold scripts we run in the terminal, in this case make-game-data.ts will hold the code that turns typescript to a JSON file for every game scene.
The Minimum Data
In 0.ts let's create a simple object with an entities object that holds the entities for the game. Let's write something with the right format, to turn into json for our first scene.
From Code to Data
Now, let's write the make-game-data.ts script. This script will automate the process of converting our TypeScript data files into JSON files that our game engine can easily load over a network.
We'll use Node.js's built-in path and fs modules for file system operations and path manipulation.
Open scripts/make-game-data.ts and paste or type the following code:
To understand this script, we start at the bottom.
-
AllGameData()runs and reads the folder we've declared inGAMES_DIR. -
We skip the Shared Directory, as that's not a game itself.
-
Then we iterate through the
scenesfolder in each game to complete the scenes one by one. -
await import()does the work of loading each.tsfile and -
Changing it's name to end with
.json. -
JSON.stringifyshould be familiar to JS developers. We want it indented to make it human readable. -
And we write the file to the
OUTPUT_DIRdefined at the top of the file.
If you duplicate the FirstGame folder and name it SecondGame. You've got another complete seperate game now. One could be a 3d platformer named PlatformerLike the other a 2D board game or anything else you can think of. Name them however you'd like.
Shared is a folder that will hold data used by all games, so as not to repeat ones self.
Okay, so let's see what happens when we run the script/make-game-data.ts.
Did you get an error like this?
Sadly there's one more hoop to jump through to run typescript files from the terminal.
Running typescript files in 2025
The easiest way is to install tsx globally.
I've tried the npm modules vite-node & ts-node and determined tsx is the best in class way to run typescript from the terminal in 2025.
Then we can always run typescript from the terminal in 2025.
We can see there are new .json files in the public/GameData folder. This public folder is where we'll be downloading static files to setup a game scene.
Every scene is the same in that it's a complete refresh of the browser. So scenes can represent anything from a new game world to a mini-game with completely different code and asset needs.
Watch the Data Folder with Vite

So now that we have the static .json files building from the command line. We want the data folder to automatically rebuild on changes. For that we can use a simple custom vite-plugin defined in vite.config.js:
Let's install a new package in the terminal.
We'll use a library to do better cross platform watching. In vite, plugins can be defined as a object with a name and a configureServer property which is a function that has the devServer as its first argument.
Custom Reloading Vite Plugin
The vite plugin is basically an object with a name and a configureServer function. server is an argument and can be configured, in this case to reload the browser after running our npm run games command.
Now, in the defineConfig itself,
-
We set the watcher to watch the data folder. It watches all files in their recursivey.
-
Next we define the
execlibrary to spawn a process to run the games script just like it was the command line. -
If there's no error we send a websocket command to the browser telling it we need a full reload.

In Sum
In this article we creating a data-driven approach to our games. In the next one we'll get started implementing the Game code logic and logic, while keeping the data seperate in the .json files.