Dispatch from Command. The star map is the heart of X-Wars - and on phones it had started to feel like dragging a heavy painting instead of flying through space. Today I am shipping a new default renderer built on WebGL (via PixiJS), keeping fog and occupation visible when you zoom out, and leaving the old path as a kill-switch until the new one has soaked in production.
Why the map felt slow
A living star map is not one picture. It is a moving camera over a growing world: tile grids, exploration haze, beacon occupation tints, suns, planet sprites, fleet pins, transit trails, scan rings, and reachability previews. On a laptop the old approach often looked fine. On mid-range Android and iOS it stuttered - especially with large occupation disks or a wide explored region. Pan and pinch felt late. That is not a content complaint. That is a renderer tax.
How a huge universe is stored without drowning the browser
The universe is large on purpose. Commanders do not download every tile as a row of JSON. The server and client cooperate on sparse structures - only what you have revealed, discovered, or need for the current view.
Exploration fog as bitmaps
Fog of war is not a list of every dark tile. Revealed space is stored in chunked bitmaps - fixed-size squares of the universe packed into bits. A 64 by 64 tile chunk fits in a few hundred bytes. The browser receives the chunks that touch your map bounds, not a novel of coordinates. When a fleet reconns a disk, we set bits and send patches. That is how fog stays cheap to store even after months of exploration.
Occupation as disks, not wallpaper tiles
Beacon territory uses Chebyshev distance - max of absolute dx and dy - so a coverage radius is literally an axis-aligned square on the tile grid. Tiers stretch that square from small patrol footprints to enormous claim disks (tens of tiles on a side, up to about 100 for the heaviest modules). The game does not need to store every occupied tile as its own document. Ownership is reconstructed from active beacon centers and radii, with planet body tiles punched out of the claim. Overlaps between your own beacons stay one flat tint, not a stack of darker layers.
What the map API actually sends
A map load is a pinboard, not a texture atlas of the cosmos: systems you know, fleets you own or detect, beacons whose coverage intersects your fog or recon, decay salvage you have found, and bounds wide enough to hold those anchors. Exploration chunks arrive alongside. The client then decides what to paint for the current camera. That split - sparse world state on the wire, dense pixels only for the viewport - is the only way a browser MMO star map stays honest at scale.
The old renderer - honest post-mortem
The previous star map was a React DOM world: a huge layer moved with CSS translate and scale, pins as positioned buttons and images, fog and occupation as SVG rectangles. That was the right first ship for alpha - interactive, debuggable, and fast to iterate. It did not age well once occupation disks and explored fog grew.
- CSS-scaling a world-sized layer forces the browser to composite a giant tree of nodes on every pan frame.
- Occupation painted one SVG rectangle per occupied tile inside the viewport after expanding full Chebyshev disks in JavaScript - correct, and expensive.
- Fog used merged SVG rects over the loaded canvas - better than one node per tile, still SVG-heavy as reveal grew.
- Planet and fleet pins were real DOM elements with filters, rings, and hit targets - fine in dozens, costly in hundreds under a transforming parent.
- Zooming out used to drop fog and occupation entirely so the macro view could survive - which hid the intel you most needed when surveying the theatre.
The new renderer - WebGL with PixiJS
The star map now draws into a viewport-sized canvas through PixiJS, which talks to WebGL (with a safe fallback path when needed). The world is no longer a billion-pixel DOM sheet. It is a camera matrix over GPU-friendly draw calls. HUD docks, dialogs, and command chrome stay React - only the living map surface moved.
Camera without punishing React
While you pan or pinch, the camera transform updates the Pixi stage immediately. React still learns about focus and cull bounds on a calmer cadence - quantized focus steps and gesture end - so we are not rebuilding the universe on every pixel of finger travel. Moving fleets and transit trails live in a dynamic layer that can tick without remounting suns and fog.
Layers that stay useful when you zoom out
Level-of-detail still exists, but it changes representation - not whether fog and occupation exist. Zoomed in you get tile grids, planet sprites, and crisp pins. Zoomed out you get coarser grids, sun clusters, and simpler markers - while occupation squares and fog haze remain so the strategic picture does not go blank.
- Background: grid, fog, occupation tints, range outlines (beacon link, fleet detect, move reachability, scan radar).
- Bodies: suns, planets, beacon markers, salvage pins.
- Dynamic: fleet markers, transit paths, travel-plan previews, merge arrows.
Why Chebyshev disks matter for drawing
Because a Chebyshev disk is a square, occupation can be drawn as one quad per beacon instead of thousands of tile rectangles. Fog still uses merged revealed regions, but only for what the viewport needs. That is the difference between painting wallpaper and stamping stamps.
What you should notice as a commander
- Smoother pan and pinch on phones, especially over occupied or well-explored space.
- Fog and occupation still readable when you zoom out to plan the next corridor.
- Selected fleet detect range and beacon coverage previews drawn as clean squares on the map.
- Same gameplay rules - this is a renderer change, not a redesign of fog, beacons, or fleets.
Kill-switch and alpha honesty
Pixi is the default. If something goes wrong in the wild, I can flip the live default back to the legacy DOM path without a full rebuild. Already-open map tabs keep their current renderer until you reload. I am keeping the old path for a short soak window on purpose - about a week of real play - then I intend to remove it once I trust the new glass.
If the map still hitch on a specific device after a refresh, tell me through Command Relay with device, browser, and roughly where you were looking. The goal is simple: the star map should feel like space again - light under the finger, dense with intel, and ready for the fights still ahead. — Command
