diff --git a/src/lib/content/blogPosts.ts b/src/lib/content/blogPosts.ts
index 18e0139..1c016fa 100644
--- a/src/lib/content/blogPosts.ts
+++ b/src/lib/content/blogPosts.ts
@@ -1,6 +1,16 @@
import type { BlogPost } from '$lib/model/BlogPost';
import { asset } from '$app/paths';
+export const dataDrivenSystems: BlogPost = {
+ id: 'data-driven-systems',
+ title: 'Game engines, Sliced bread, and data-driven systems',
+ description: 'Designing data-driven systems by separating behavior from content.',
+ date: '16/03/2026',
+ image: asset('/images/data-driven-systems/sliced-bread-yaml.png'),
+ tags: ['games', 'overengineering'],
+ path: '/(app)/blog/(posts)/data-driven-systems',
+};
+
export const piano: BlogPost = {
id: 'piano',
title: 'Video game piano',
@@ -34,16 +44,4 @@ export const foolsball: BlogPost = {
path: '/(app)/blog/(posts)/foolsball',
};
-export const blogPosts: BlogPost[] = [
- // piano,
- // {
- // id: 'unique-puzzle',
- // title: 'Unique Puzzles',
- // description: 'A short story about the awesomeness of puzzles',
- // date: '01/01/2026',
- // image: '',
- // tags: ['games'],
- // path: '/(app)/blog/(posts)/puzzles',
- // },
- beatBox,
-];
+export const blogPosts: BlogPost[] = [dataDrivenSystems, beatBox];
diff --git a/src/routes/(app)/blog/(posts)/data-driven-systems/+page.svx b/src/routes/(app)/blog/(posts)/data-driven-systems/+page.svx
new file mode 100644
index 0000000..732cc7a
--- /dev/null
+++ b/src/routes/(app)/blog/(posts)/data-driven-systems/+page.svx
@@ -0,0 +1,100 @@
+
+
+Years ago I released the [Incremental Game Template](https://123ishatest.github.io/igt-docs/) (IGT) which I then called "*A collection of useful scripts to help you develop incremental games*".
+While that was technically true, it served mostly as an archive for me to store all the game development work I had done over the years.
+As the template grew it not only contained more game mechanics, but also more concrete implementations of my games.
+It became more and more difficult to separate mechanics from content, making it nearly impossible for people who are not me to benefit from the project.
+
+Today we will dive into those distinctions alongside the lessons I've learned deprecating IGT, and how my new game engine [Ludiek](https://ludiek.123ishatest.com) does everything way better.
+
+## Behaviour vs Content
+Over the years I have become a big proponent of separating behaviour from content.
+This is most prominent in applications with a large amount of content, such as games.
+But I believe keeping this divide in mind will help you design cleaner applications no matter what you are creating!
+
+- *Behaviour* encompasses the logic of your application, decisions that need to be taken based on the state and content we are operating on.
+- *Content* is the static data of your application. Be it items in an RPG, routing tables in an SPA, Content in a CMS. It is *not* state.
+
+One advantage becomes immediately obvious, the implementation of behaviour is pure and deterministic.
+This improves testability, composability and maintainability!
+
+## In practice
+Enough theory crafting, what does it look like in practice? What went wrong with IGT?
+IGT contained functionality for `Items` and `Inventory` as most games use some sort of an inventory system.
+In its most basic form it is a way to track how many you have of certain items.
+Some items have special interactions: Materials can be processed, Armour can be equipped, and Consumables can be... consumed.
+Here is how we would define a consumable `Bread` item in IGT, it restores 10 health when eaten.
+
+
+```ts
+class SlicedBread extends Consumable {
+ public name = "Sliced Bread"
+
+ public consume() {
+ player.restoreHealth(10)
+ }
+}
+```
+
+On first sight it looks sensible, there is little boilerplate and the consume function is succinct.
+But what if the `consume` function grows more complex?
+What if we have different kinds of food that all trigger the same code when consumed? We'd have to repeat the consuming logic everywhere.
+But even worse, this game content is now defined in code, meaning game designers need to dive into the codebase to balance the game.
+They don't like that.
+
+Let's separate the behavior from the content! We need to restore health based on the provided amount.
+```ts
+class RestoreHealth extends ConsumableEffect {
+ type: 'restore-health';
+
+ public args: {
+ amount: number,
+ }
+
+ public apply(args) {
+ player.restoreHealth(args.amount)
+ }
+}
+```
+
+And the content becomes much cleaner!
+
+```yaml
+# sliced-bread.item.yaml
+name: Sliced Bread
+onConsume:
+ type: restore-health
+ amount: 10
+```
+
+While there is an initial investment of having to create the `RestoreHealth`, we now have it forever.
+Every item can be turned into a consumable by adding 3 lines of data, and no extra code.
+
+That is the essence of data-driven design: Isolate behaviors as small as possible, and let your static data compose it to achieve your desired behaviour!
+
+Game designers often believe that data-driven games lose some of their magic.
+When all your content has to adhere to rigid systems, unique mechanics are more difficult to implement.
+While this could happen, realise you are expecting your developers not to overengineer a system that can support even your wildest dreams.
+
+## Ludiek
+
+Speaking of wild dreams, with this new data-driven approach I have been designing and building [_Ludiek_](https://ludiek.123ishatest.com/), the game engine that focuses on the fun.
+It is the spiritual successor of IGT, but with a plugin-based architecture so you can mix and match whatever you need!
+
+Today we mostly discussed moving from level 1 towards level 2, but Ludiek pushes all the way to level 3!
+
+```ts
+// level 1 // level 2 // level 3 // Level ∞
+if (money > 100) { if (money > upgrade.cost)) { if (canAfford(upgrade.cost)) { do()
+ money -= 100 money -= upgrade.cost; spend(upgrade.cost)
+ power += 2; power += upgrade.powerGain; apply(upgrade.benefit)
+} } }
+```
+
+With these abstractions we can create plugins that operate on the most abstract of concepts.
+
+If you are curious, you can read more on it [here](https://ludiek.123ishatest.com/docs/introduction/welcome), or stay tuned for the next blog post!
+
+Thanks for reading!
diff --git a/static/images/data-driven-systems/sliced-bread-yaml.png b/static/images/data-driven-systems/sliced-bread-yaml.png
new file mode 100644
index 0000000..56150d2
Binary files /dev/null and b/static/images/data-driven-systems/sliced-bread-yaml.png differ