• [AoNW] Fog of War: Separating What Exists from What the Player Knows

    Fog of war looks like a visual feature. The map gets darker. Unknown territory disappears. Previously explored land stays dim. Enemy units appear and vanish. It feels like something that belongs mostly to rendering.

    But in AoNW, fog of war is not just an overlay. It is one of the systems that forced me to separate three different ideas:

    • what exists in the game world
    • what a player has discovered
    • what a player can currently see

    That distinction matters everywhere. It affects rendering, selection, movement, combat previews, AI decisions, event visibility, and eventually multiplayer.

    (more…)
  • [AoNW] Rendering a Hex World with Flutter and Flame

    Age of New Worlds is built in Flutter, but the map itself is not a normal Flutter widget tree.

    That was one of the first architectural decisions I had to make. A 4X game has a lot of ordinary UI: menus, panels, buttons, overlays, localization, routing, settings, loading states, and HUD elements. Flutter is excellent for that.

    But the game map is different.

    (more…)
  • [AoNW] Commands, Reducers, and Why the Renderer Does Not Own the Game

    When I started building AoNW, it was tempting to let the map renderer become the center of the game.

    That would have been natural. The renderer is where the player clicks. It knows which hex is under the pointer. It owns the camera, visual layers, hover states, unit markers, movement previews, fog overlays, particles, and the general feeling of interacting with the world.

    But in a 4X game, that is exactly why the renderer should not own the game.

    (more…)
  • [AoNW] What I’m Building

    Age of New Worlds is my attempt to build a hex-based 4X strategy game for iOS, MacOS, Android platforms with the kind of systems I love: exploration, expansion, city growth, production choices, research, turn pressure, and the slow emergence of a readable strategic map.

    At the current stage, the game already has the core loop in place. I can start a match, explore a hex map, found cities, move units, manage production, choose research, improve tiles, handle turn flow, and save or load the game. There is also a map editor and a growing set of developer tools around balance and content iteration.

    The interesting part, at least for this series, is not only what the game does. It is how the project is shaped so it can keep growing.

    (more…)
  • Fast Sylius Plugins Contribution Setup

    If you want to start contributing to a Sylius plugin and don’t want to waste time on manual setup, DDEV is a great tool that helps you configure a working environment in just a few minutes.

    In this post, I’ll show you how to do it using SyliusTpayPlugin as an example. This project is a perfect fit — not only because of its technical specifics, but also because it’s active, you can get valuable code reviews, and it’s a great starting point for your Open Source contributions.

    (more…)
  • Experimenting with Event Sourcing and Ecotone

    I’ve just published a new repo, a side project where I’m experimenting with Event Sourcing, CQRS, and the Ecotone framework in a Symfony 7 environment.

    This is a personal learning project, not something production-ready. The goal is to better understand how to design event-driven systems in PHP using real-world structures like aggregates, value objects, and projections. As a playground, I’m building a turn-based strategy game (inspired by Civilization) -just enough to have a meaningful domain to model.

    Right now, the repo includes:

    • Symfony 7.3 backend with Ecotone (commands, events, projections),
    • Early frontend setup using Vite, Symfony UX and PixiJS for rendering a hex map,
    • A bunch of evolving domain logic for turns, players, and cities.

    Again – this is an experimental setup for learning, so expect the code to change frequently. But if you’re also exploring Ecotone or curious how event sourcing might work in a Symfony project, feel free to check it out, leave feedback, or just follow along.

    github.com/ernestwisniewski/symfony-of-ages

  • Symfony 7.3 – New features that grabbed my attention

    Symfony 7.3 may be a “minor” release, but these five additions will shave boilerplate off everyday code, boost performance where it hurts and generally make life nicer for Symfony developers.

    (more…)
  • Visiting the Westkapelle Lighthouse

    I recently had the chance to visit one of the most iconic landmarks on the Dutch coast – the Westkapelle Lighthouse. It’s not just a beautiful structure but also a place steeped in history, guiding ships through the treacherous waters of the North Sea for centuries.

    (more…)
  • The 1953 Flood in the Netherlands: A History Lesson at the Watersnoodmuseum

    Living near the Watersnoodmuseum, I had long wanted to visit this place and explore the history of one of the greatest natural disasters in the Netherlands—the 1953 flood. The museum is located in Zierikzee, on the island of Schouwen-Duiveland in the province of Zeeland. It was here, on February 1, 1953, that nature struck with unprecedented force, flooding vast areas and claiming the lives of more than 1,800 people.

    However, beyond being a history lesson, the museum combines education with interactive learning. Multimedia exhibits, simulations, and games help visitors understand the mechanisms behind storms, their consequences, and methods of protection. The museum’s surroundings—beautiful nature and the proximity of water—make it a unique place on the map of the Netherlands.

    (more…)
  • Projections – Transforming Events into Read Models

    In an event-sourced architecture, the entire history of changes to the application’s state is stored as a sequence of events. However, to effectively work with this data, we often need optimized read models. This is where projections come into play. In today’s post, I’ll show you how to set up and implement projections in Ecotone, allowing you to easily transform events into the current state of your system.

    (more…)