Kaizen is an interactive slice-of-life roleplay game developed by Fate Forge, earning over 29.8 million visits and 95K monthly active users. The game is set in a fictional Japanese town called Kaizen, where players can create characters, customize their homes, and use provided facilities to socialize and develop their characters. The game was developed on Roblox using their Luau language.
Originally freelancing for this project in 2022, I was able to satisfy my client and took on a role in maintaining the game. My role as the programmer involved programming gameplay, UI/UX, datastores, networking & replication optimization, and tools to improve the proficiency of our builders & designers. As of 2025, I now manage the project entirely.


Reducing GPU usage has been a major performance challenge in this project. Roblox provides a built-in LOD system, but it is bundled with other systems that can negatively impact performance, and its LOD model generation is automated and difficult to control. To solve this, I developed a modular LOD controller that manages the detail state of registered objects while providing a developer-facing interface.
The controller uses a custom octree data structure to efficiently query objects within a radius. Octrees are well suited for spatial queries involving many objects because they partition space to reduce search complexity. Query results reuse the same arrays to avoid per-frame memory allocations. Each result also stores the frame it was last seen, allowing the controller to determine whether an object should be in high or low detail.
Currently, the system supports two LOD states: high and low, using callbacks to define how objects transition between detail levels. Separate high and low detail radii reduce noticeable popping and prevent rapid LOD switching. Each LOD controller instance can be configured per object type. Objects can be added directly via AddInstance(instance) or through helper scripts that detect tagged objects and call AddInstance(instance) automatically. The controller itself does not manage tags, allowing developers to initialize data on tagged objects for use in their callbacks.
Controller configurable properties can be found below:
| Property | Type | Description |
|---|---|---|
| Active | Boolean | Determines if the controller should be active. |
| UpdateInterval | Float | Controls how frequently the controller updates object LOD states, in seconds. |
| HighDetailRadius | Float | The range where an object switches to high detail. Cannot be lower than LowDetailRadius. |
| LowDetailRadius | Float | The range where an object switches to low detail. Cannot be higher than HighDetailRadius. |
| OnHighDetail | Function | Callback fired when an object should switch to high detail. |
| OnLowDetail | Function | Callback fired when an object should switch to low detail. |
These are only two examples of how LOD is implemented using the system and its tools. The callback-driven architecture makes it highly versatile, allowing developers to define custom behaviors for different object types. The system has proven effective in large scenes, with minimal runtime overhead and significant reductions in render time and draw calls.
An issue that developers often struggle with on Roblox is tween syncing across all connected clients. Naturally, a developer would decide to let the server handle the syncing. However, many developers will tween game objects (instances) through the server. This results in terrible animation frame skips as clients generally have varying ping. Additionally, network and CPU usage drastically increases, resulting in lower performance on some low-end clients like our mobile player base. It is important to note that server updates tend to have more latency than render updates, which results in the animation frame skipping. Animations should never be handled on the server and games should instead rely on the client to perform the animation.
Unfortunately, this problem was present on Kaizen. Aiming to improve the programming quality of the game, I did my best to update and improve all legacy code. As a solution, I created a ReplicatedTweening module to handle tween replication between the server and the client. Instead of the server handling the animation then replicating each animation frame to the client, the server only send the tween information to each client and expects the clients to perform the animations themselves. After the tween ends, the server would simply apply the final value of the tween to the game objects. This way, the client handles animations and the server can still use up-to-date values for the game objects that it manages.
In the event that the tween is canceled through manual assertion of a new value, the server would simply cancel the thread which handles applying the final value of the tween. The client also reacts this way due to the way the engine works. ReplicatedTweening also allows for callbacks upon completion and the ability to only tween an object for specific players. ReplicatedTweening resulted in a significant decrease in CPU and network usage, with most of the network usage being the initialization call.
The module can be found in the GitHub repository below.