From: 08 Mar 2026, 12:58 , updated: 09 Mar 2026, 22:01

Main mechanic, blockout and workflow stuff

The phasing light

As you may have seen last week, I uploaded a GIF where a light is phasing. I think I may have forgotten to mention how important that actually is. This is basically the main function in the game. Everything should take this into account.

The player should not read this through a HUD, but rather feel it. That is why I wired it into the shader effect I made last week.
You remember? The one where the screen gets pixelated and kinda JPG-ified. Yeah, that one.

Based on the sine wave, pixelation and levels are controlled according to their base value.
newPix = initPix + (float)Manager.Instance.newSine * _pixModifier;
So basically:
If the sine is near -1 and _pixModifier is also something negative, the pixelation effect gets stronger.
If the sine is near +1, the pixelation effect gets weaker.
Same idea for levels.

And by the way: the animation from the GIF is of course sped up. The effect will not be that fast ingame. I want this to be subtle.

Of course, this will not be the only thing telling the player subliminally how to feel... or how the player character feels. But it is something I believe can help translate between ingame character and player if done right. Let's see...

Preproduction in Godot

Right now I feel like I have at least a basic understanding of Godot, so I finally started the blockout / preproduction phase.
Thanks to CSG, or constructive solid geometry, it is relatively simple to create levels, and even in a non-destructive way. Mainly for prototyping of course,

Image
Image

Here comes the usual Unity comparison: I think Godot wins this one again.

Unity has a tool called ProBuilder, which is great. I genuinely liked it a lot. I even thought about building my production level with it back then. But when I used it, doing something as basic as cutting a door hole was just not very straightforward. Maybe there is a boolean tool now, but back then I either didn't have it or didn't find it, so I ended up doing it the long way.

A small clip showcasing Godot's "Boolean Tool"
A small clip showcasing Godot's "Boolean Tool"

Example: you want to make a 3x3x3m cube with a 2x1m door. In ProBuilder, or at least the way I did it: you basically have to build the layout so the doorway already exists in the topology. Start with the floor, extrude until the door area, stop, extrude around the door opening, stop again, finish the floor. Then extrude edges up for walls, make sure you have the seam where the door is, then delete faces. And then you notice you also nuked faces inside the doorway, or created weird inside faces, and now you have to fix that too.

Basic room blockout showing pre-built wall topology for a doorway opening, highlighted in red
Example of a basic room where the doorway had to be planned into the topology from the start instead of being cut out afterwards

You get the idea. It works, but it is just kinda tedious for something so simple.

In Godot, you create one 3x3x3m cube, flip normals so you can work with it like a room, then create another one that is like 2x1x0.1m, position the second one where the door is supposed to be, select subtraction... done.

Things that took some getting used to

There were basically two or three things that took a bit of time to understand.

The images below are basically the same setup, just reordered. And that already changes the result. So a cutter does not just subtract from everything.
It only affects whatever is part of the result up to that point in the chain.

Godot CSG example where the node order prevents the cutter from affecting the whole shape
With this node order, box3 only affects the result up to that point in the hierarchy
Godot CSG example where reordering the nodes makes the cutter affect the combined shape
With this node order, box3 affects all the items in this scene

Secondly, if you want “real” rooms, you usually want wall thickness. So you do not just make one inverted box and call it a day.
The clean way is: make the outer box (your building shape) and then subtract a slightly smaller box inside it. That gives you actual walls.

This matters if your room is supposed to be visible from both the inside and the outside. Otherwise you end up in situations where you cannot look outside from the inside, but you can look inside from the outside. Or the other way around, depending on how you flipped normals. Either way, it looks wrong.

POST RELEASE ADDENDUM:

I realized something right after writing this. It is actually even easier than I thought.

What I described above is the way I first approached CSG.
Basically building rooms as hollow shapes. So, make a box, flip normals or subtract a slightly smaller box from it, and now you have a room shell with wall thickness. That works, and for quick room prototyping it is still totally fine.
But for larger architectural blockouts, that is not the easiest way to think about it.

What works much better is to start with a solid mass first, and then subtract the walkable space out of it. So instead of building a hallway, a staircase, and separate room shells piece by piece, you begin with one big block that represents the building volume, and then carve the hallway, rooms, etc out of that.

That sounds almost too obvious in hindsight, but it immediately made blockouts feel way more natural. Instead of placing objects in empty space and hoping they somehow read like architecture, you are defining the empty space inside a larger structure.

Rough Godot CSG blockout of stacked interior floors around a tall central void.
This is where it really clicked for me. Even in this super rough state, the subtractive mass-first approach already reads more like an actual building than the old room-shell workflow.

Local development with DDEV instead of suffering

I also set up DDEV for local development, because I am simply not in the mood to set up Docker Compose properly just to mirror my webserver environment.

A few things had to move around / change for Docker Compose to work the way I wanted, but now everything is nicely packed and just works. HTTPS is preconfigured, routing is nice, and there is no hassle.

Also: in the event that I do end up sending mail from there (which I most likely won't) I can catch it. So that is nice too XD

Workflow overhaul

I also finalized the workflow overhaul.

By moving to DDEV, the goal was to develop locally while also making deployment easier. That led to some overhauls and refactorings that had to happen. But in the end, they actually improved the previously flawed system.

I also noticed even more architectural issues. However, those could also be interpreted as creative liberty :D
Anyways, I can now create an extension, add it to the root composer.json, develop it, test it, etc. If it is done, I push everything with a tag, go to the server, add the require there as well, run update, done.

Much better than rawdogging everything :x
And it is even versioned.

Also, thanks to the refactorings, you can now just pull the template wherever you want, create an .env.php in the config directory based on the provided example, run composer install (or ddev composer install if you are working with DDEV) and... it should just work.

At least I hope so. Let me know if it doesn’t :x

Migration system and stronger foundations

I even implemented a migration system that runs after each Composer update.

It checks every extension (including the core, of course, which runs first) and searches for files in:
{ext}/backend/private/Repository/Migrations/*.sql
Then it checks whether a migration has already been executed by looking at extension name + SQL file name. If it already exists, it gets skipped. Otherwise, it runs.

So yeah, not much user-facing change has happened. But the foundation is stronger than before, and I do not have to worry as much anymore about leaking everything when dumping something.