Lacuna is a two-player strategy game where the board is constructed during play. Instead of starting with a grid or hex map, players start with an empty circle. Over the course of 30 to 60 minutes, they draw colored strands inside the circle, building up a planar graph whose topology determines the score. When a region becomes completely enclosed by strands of a single player's color, it becomes a "Lacuna" and scores for that player.
I designed the game and its rules from scratch. The physical version would be playable with colored pens and a printed circle, but the topology tracking and scoring would be tedious to do by hand. The digital implementation handles all of that automatically.
How a turn works
At the start of each turn, the active player draws a tension token, choosing one of two options. The tension value determines how many strands the player can place that turn. They then position a node inside a region and trace paths from that node to vertices on the circular boundary, using intermediate waypoints to route around existing strands. Strands cannot cross. As the game progresses, the available space fills up and routing becomes increasingly constrained. The early game feels open and strategic; the late game feels like threading a needle.
The game ends when no legal moves remain or when the tension token supply runs out.
Detecting enclosed regions
The core technical problem is determining, after each strand is placed, which regions of the circle have been enclosed and what colors their boundaries are. The strands and the circle boundary together form a planar graph. The faces of that graph (the regions between strands) need to be enumerated, and each face's boundary needs to be traced to check whether all edges belong to a single player.
The face enumeration algorithm walks the planar graph, following edges and tracking which side of each edge it's traversing. When it returns to the starting edge having traced a complete boundary, it has identified one face. The algorithm runs after every move, because any new strand potentially splits an existing face into two or seals a face that was previously open.
This computation has to be fast. Players expect to see immediately whether their move created a Lacuna. The tricky cases involve strands that share vertices, strands that touch the boundary at multiple points, and degenerate face configurations where a very small region is created between closely spaced strands. Getting the edge-traversal logic correct for all these cases took significant testing.
Rendering with SVG
The board is rendered in SVG rather than Canvas. The primary reason is hit-testing: in SVG, each strand is a DOM element with native event handling. Selecting a strand, highlighting it on hover, or detecting which region the user clicked in all come from the DOM for free. In Canvas, all of this would need to be reimplemented with manual coordinate math and spatial indexing.
Strands are drawn through waypoints using Chaikin's corner-cutting algorithm. Chaikin smoothing iteratively replaces sharp corners with smooth curves by subdividing each segment and cutting corners at 25%/75% positions. After a few iterations, the result is a smooth curve that passes near (but not exactly through) the original waypoints. This gives the strands an organic quality, like thread stretched between pins, rather than the angular look of straight line segments between points.
Multiplayer
Lacuna is played online between two players. The game state is synchronized in real time through Firebase Realtime Database. One player creates a game and receives a shareable link. The other player opens the link and joins. Firebase Anonymous Authentication assigns each player an identity without requiring account creation.
Because Lacuna is strictly turn-based (only one player can act at a time), there are no concurrency issues to resolve. The game state is a single Firebase document containing all nodes, strands, scores, and turn information. Each move is an atomic write that both clients observe in real time.
The rulebook and visual output
The repository includes a formal rulebook, written in LaTeX and compiled to PDF. Writing unambiguous game rules is a different kind of challenge from writing code. Every edge case needs to be addressed in a way that a player can understand without a computer to adjudicate.
One thing I like about Lacuna is that the finished boards are visually interesting. Every game produces a different pattern of colored curves partitioning the circle into regions. The results tend to look like stained glass or river deltas. There's an aesthetic payoff to a game where the artifact you build during play is the board itself.