Dev Log — September 2026
Hi everyone!
Since the last dev log, I've continued work on fortune cards, the PvE overhaul, and dynamic avatars.
Deko drew some amazing dolls for the game last month that, similar to the dynamic avatars, change their appearance based on the character's traits, and this proved to be an excellent opportunity to improve our rendering pipeline for the game in a way that also prepares us for adding dynamic avatars to the game!
Dynamic Item & Avatar Rendering
Why we are moving away from Live2D
Previously, I planned on using Live2D for dynamic avatars, but the issue that kept giving me anxiety about the dynamic avatars is how poorly structured Live2D is for handling customizable characters that require numerous texture sheets and long-term maintenance.
Live2D works by importing a PSD file into its editor, where you can then turn layers into meshes and textures that can be animated. The issue is that the Live2D editor doesn't maintain a proper record of the original PSD, meaning when you update the PSD, you have to reimport the file into Live2D, and the editor struggles to recognize and connect previously and newly imported layers. This leads to duplicate layers and layers not being updated properly (because the changes were added as a new layer instead). To solve this, you'd have to clean up the editor file after each import, which becomes a daunting task for complex avatars with many layers. Live2D is much better suited for avatars where you either make small, rare adjustments after release or big overhauls, and struggles to provide a scalable solution for incrementally growing avatars like what we need.
Another issue I fear with Live2D is performance, since it doesn't support rendering multiple canvases. A canvas is a square on the screen that renders from the GPU and essentially becomes an image. When you need to display models in different contexts inside the game, you'd need to have canvases to control where the model is rendered. Since Live2D doesn't support multiple canvases, or indeed, running multiple instances of Live2D in the same HTML scope, you'd have to create an iframe for each canvas and then run a separate instance of Live2D inside each iframe!
I suspect anyone with a little HTML experience will already understand the immense performance impact of such an architecture, let alone how tedious it would be to create a proper pipeline for updating avatars when you have to communicate between iframes. Furthermore, whenever you change the parent of an iframe element in HTML, you reload its content, meaning you re-instantiate the Live2D instance and model within! The startup process for Live2D is quite heavy too, and I have experienced it causing severe stutter on multiple devices.
Having looked at the JS code provided by Live2D for running their models in HTML, I also get the impression it's been written by C++ programmers with a superficial understanding of JS and TypeScript. A lot of the code is quite frankly poorly written and badly optimized, and it bothers me that a system that runs critical frame-by-frame computations for updating vertex positions, in order to animate a 2D sprite, doesn't have any native code. Native code is C/C++ code compiled to WebAssembly, which allows it to run mathematical calculations much more efficiently; ideal for updating an array of vertex coordinates, and the fact that the developers behind Live2D didn't make a WebAssembly module, despite seemingly employing C++ programmers, baffles and worries me.
Suffice it to say, I'm not confident Live2D is the right tool for Battle Mages, and therefore I decided to create our own custom rendering pipeline for the game that is easier to maintain and expand, has no third-party dependency, and that I know will be efficient at handling avatars so the game will continue to run well on any device it runs well on today.
To accommodate Deko's workflow for the dynamic avatars, they will now use a PSD file directly, similar to items with dynamic coloring, since avatars will also need to support dynamic coloring on top of supporting an expansive number of character traits and equipment.
The good news is that I've already created the new rendering pipeline for handling item and avatar models with dynamic coloring and other traits, and it's currently being used on the test server!
The new rendering pipeline
The challenge with items like the sex dolls is that their appearance changes based on the character's traits: 5 different natures, 4 different breast sizes, 2 different genitalia, and almost 100 different dynamic colors. 5x4x2x100 is 4.000 different images, and if we add support for more traits, which we want to, that number increases exponentially! —This, together with support for dynamic avatars, is why we need to be able to render images locally. Instead of storing images for every combination, we create a PSD file with layers for each trait, and we will then render the combinations we need locally from the PSD.
Previously, only the website server would handle dynamic coloring of items, using layered PSD files, and the website acts as a CDN (Content Delivery Network), where the client can ask for images in a particular size and optional color. The CDN prepares images for all sizes and color variants and stores them online so they are ready to be delivered on demand. Since the game supports screens up to 4K, the CDN speeds up download time and increases rendering quality by sending smaller images to devices with smaller screens, and dynamic coloring has already been pre-baked into the delivered images.
Using modern service worker browser technology, dynamic coloring can now also be applied locally for select items and dynamic avatars!
Service workers allow us to intercept calls to the website, so we can return a locally generated response, and we use this to intercept calls to the CDN in cases where we want to perform the rendering locally instead. Since older browsers don't support service workers, the system has been designed so any browser without service worker support will seamlessly fall back to using the CDN; however, since the CDN won't store all trait combinations for items like sex dolls, it won't always be able to show traits accurately. The game will also continue to use the old static avatars on browsers that are unable to render the dynamic avatars for any reason.
Workers also have the benefit of being multi-threaded, meaning heavy CPU operations performed by the worker can be done on a different CPU core without stalling the main process.
On startup, the game client will start the service worker and download a small data package containing information about models and items that need to be rendered locally, and the location of related assets. When it intercepts a call to an item image, it will instead download the PSD file and create the image from it. To reduce the download size, PSD files are packaged into ZIP files on the server and unpacked by the service worker. Related files, like the PSD for when an item is worn and another PSD for when it's in the inventory, are stored in the same ZIP file to further improve compression.
When the service worker loads a PSD, it separates it into layers and writes their pixel data into a texture atlas on the GPU to optimize rendering speed and GPU memory usage. The GPU is exceptionally fast at processing pixel data, and I have written shaders that can perform all the dynamic coloring we need for items and models at incredible speed.
Another interesting perk with service workers is that they can be shared between tabs on the same domain, meaning the same ongoing background process can handle in-game graphics and the graphics displayed on the website and profiles! This also means the background process will continue to run if you refresh the game or open a profile, which is in stark contrast to Live2D that needs to instantiate a new process every time you display a new avatar.
- Worker: 1 process for any number of items, avatar models, and tabs, that stays alive between refreshes (incredibly efficient).
- Live2D: 1 process and embedded iframe per avatar model per tab, which needs to be re-instantiated every time the model is moved in the HTML DOM hierarchy (incredibly inefficient)
It took a while to finish up this system, but I can confidently say that it's well prepared and tested for when we're ready to release Deko's work on the dynamic avatars!
Unfortunately, it means we don't have access to the same smooth animations that Live2D provides, but I think it's more important for avatars to display a wide variety of character traits and eventually equipment, that the game continues to play smoothly on a wide variety of devices, and that it's easy for us to expand dynamic items and avatars in new and exciting ways!
PvE Overhaul Progress
While I used most of my time this month on the new rendering pipeline, fortune cards, and finishing up absorption-themed content for the game, I also had some time to plan and design more scenes for the game, and it led me to realize I needed to double down on two design philosophies for PvE content:
- Content shouldn't be random: if one or more players experience the same encounter, make the same choices, and get the same result in a challenge (failure or success), they should get the same scene each time. This is so that if a player experiences a scene they love, they should be able to intuitively re-experience it by seeking it out and making the same choices, without obscure or random conditions.
- It should be intuitive for authors to write interesting scenes without being encumbered by a need to support numerous conditions, like a variety of sexual preferences, character appearances and traits, content tags, or desire levels.
What both these design philosophies mean is that scenes should be driven by deliberate choice and the result of challenges, instead of trying to adapt seamlessly to a myriad of player settings and traits. These are good for PvP situations where they create necessary limits and base rules between players in an open-ended setting, but in a closed-ended PvE scene it's more important to give the player a selection of impactful and informative choices.
I already steered more in this direction when I decided that players choose the nature of the scene and what skill they want to use for the challenge at the same time, and that the outcome of a scene is decided by a combination of the result of a challenge and the card they select at the end of it.
- All scenes start by introducing the "global theme" of the scene.
- The player is then given a choice of what ability to use, each accompanied by a descriptive text that explains how the scene will progress for each ability. This affects both the nature of the scene and potential partners, and will tell the player what to expect from each choice. Choices can be variants of the same scene with a central NPC, or parallel subplots with different NPCs in a similar setting.
- After the challenge, the player will select a fortune card for their character that will directly affect how the scene plays out. If the card has to do with breast enlargement, then the scene will involve breast enlargement. If the player is successful, the scene will have a short conclusion wherein the player only suffers minor changes or inconveniences before they are able to continue their journey. If the player fails, the scene will play out to its fullest perverted conclusion.
Sex between the player and one or more NPCs generally only happens in scenes either if the player decides to use a sexual ability for a challenge, or if they select a sexual fortune card after failing a challenge. When a player uses a sexual ability, the game clearly tells the player what to expect before they make their choice. Otherwise, unprompted sex only happens after a failed encounter, and here, the Grovel skill can be used to abort unwanted sexual intercourse with an NPC.
I've also made groveling and failing challenges less punishing. If failing is punishing, groveling could be used to escape said punishment by aborting a scene before it happens, so groveling would likewise have to be punishing. By making failing less punishing, groveling can be less punishing in turn, allowing it to become more reliable and useful to players, and I want players to be able to use their "safe word" without reprisal.
For this reason, being turned inanimate in PvE doesn't lock you in the form for 15 minutes. This is a timeout in PvP that assures the victor gets to exploit their victim for at least a 15 minutes. A player might decide to stick around after, and a player who failed a challenge and became inanimate might decide to do the same. Groveling and being defeated still bar you from using Restore Self for free, so there's still a small incentive to wait out the 15-minute timer, but it's far less punishing, and failed challenges that result in animate or inanimate changes are far more balanced.
The core principle is that all time spent trying to accommodate a myriad of different player settings and traits within a single scene is better spent writing more scenes with a specific audience and predictable outcomes, and for that, we also need to make sure players can easily skip unwanted content. This will also make scenes simpler and more enjoyable for authors to write.
That's it for this month's dev log!
Thank you so much for all your support and I hope you enjoyed my development ramblings this month! ❤️
This weekend, while coming up with things for the dev log, I also finished up the narrative structure for the first few new encounters, and I'm very happy with how it's all shaping up and coming together! In the coming month, I will finish up more of these templates and start onboarding authors who want to help write PvE content for the game.
Deko's work on the dynamic avatars is also progressing steady and it looks amazing! I know we're both looking forward to sharing his work with you soon!
XOXO,
Tinon




