DEV Community

ivan kulkin
ivan kulkin

Posted on

How I made uncertainty readable in a deterministic browser strategy

I wanted to build a strategy game where tension appears before the click. Random outcomes are easy to add, but they often feel arbitrary. MYCELIUM became an experiment in exposing enough information for a risky move to feel like a decision rather than a coin flip.

The board shows uncertainty instead of hiding it

The world is generated from a deterministic seed. A frontier cell is still unknown, but its forecast comes from the same seeded biome that will resolve when the player reveals it. The UI is not inventing flavor text after the fact.

Before an attack, the player sees the final probability and the local support around the target. Eight neighboring cells matter, so territory shape affects the odds directly.

That creates a useful distinction:

  • the result can remain uncertain;
  • the inputs are visible;
  • replaying the same seed remains reproducible.

Enemy plans are objects on the board

Hostile growth is announced before it resolves. An intent stores its source, target, direction, and chance. The player gets one turn to respond.

This matters because the counterplay is spatial. You can reinforce the target, spend a rare guaranteed Repaint, or capture the source and remove the threat entirely. The intent is not a timer floating above the UI; it belongs to a living tendril on the board.

One geometric rule creates chains

The main territory rule is simple: close a same-family square perimeter of at least 3×3 and its interior becomes captured and reinforced.

The interesting part is recursion. Filling one interior can complete a second square, so a single corner may trigger a chain of captures. The implementation needs to keep searching for newly completed shapes without processing the same square forever.

The result is a board where a locally weak move can be globally correct because it completes future geometry.

Keeping the game static

The stack is Next.js 16, React 19, TypeScript, and PixiJS. Solo play runs entirely in the browser:

  • deterministic world generation;
  • local saves and records;
  • daily seeds and challenge links;
  • no account, database, or API key.

Optional 1v1 uses direct P2P rooms. The static deployment remains enough for the game itself; TURN configuration is only a connectivity fallback for restrictive networks.

The public site also contains a server-rendered lore atlas. This gives the fictional world a crawlable surface instead of hiding every piece of writing inside a canvas.

What I am testing now

The hardest question is not technical: does showing forecasts, attack support, and enemy intents produce better decisions, or just more information to parse?

I would value focused feedback on the first match:

  1. When did you first understand why a square matters?
  2. Did an announced enemy intent change your plan?
  3. Which number or preview felt unnecessary?

Play MYCELIUM: https://mycelum.vercel.app/

Source: https://github.com/vansGAMee/MYCELUM

Top comments (0)