Central banks now redeem the national money foreign banks hold, sell reserves to defend a weak rate, and cover part of strategic imports from reserves. Five repeatable technologies raise each commodity's output per unit of energy. Hostile troops on a road or sea lane sever trade, power and unit supply. Middlemen buy food to resell to neighbours at a markup, and starving regions buy before those topping up their buffers, which clears the landlocked famines. The economic map's trade graph gains a colour legend.
Production buildings are now independent private-sector agents: they keep what their output sells for, run only to the demand they can actually sell, and spend that cash on steel and high-tech upgrades when their demand grows. Grid power is a paid private flow between plants and their consumers, and regions synthesise the food their own harvest and the reachable market cannot supply.
Island regions no longer famine: a region with no reachable supplier grows its whole shortfall from energy, and grid power now feeds cities and food before the converters, so a famine never waits on a factory.
Bundles the in-progress tree cleanup that was already present in the working tree.
- Each nation has a currency and each region a private-sector cash basket, borrowing from its central bank at the bank's rate; the government may always pay, going into central-bank debt when its budget runs red.
- Resources are bought from reachable stores only: the region itself first, then same-nation regions, then foreign ones, paid for out of private cash or, for government orders, the treasury. Drawn national stores are paid to their owning region.
- A grid in deficit imports power from a reachable surplus grid instead of a market fallback; downgrading a building no longer refunds anything.
- The monthly budget lists each resource's economic value, expands to a resource-to-source tree and keeps a cash figure beside it.
- Regions report what their people went short of over the day; starved research buildings and power-starved works raise a private daily notice.
- The city panel gains a Resources tab: reserves per resource, their market value and the private sector's daily consumption.
- Five resources (energy, steel, food, luxury, high-tech) with per-city stores, a world market, delivery and material upkeep.
- Resource-producing tile works built outside cities; every nation opens with the works its economy needs.
- Real game-icons.net art replacing the dummy icons for the new resources and works, with the credits updated.
- An aircraft now returns to the nearest friendly airport instead of always its original home, so a plane rebased to a forward airfield can strike targets beside it; the browser mirrors the rule.
- A pillage's popularity cost is an instant shift that drifts back, not a generation-long grudge. Popularity and approval read the base opinion, while the grudge stays as the diplomatic memory.
- Doubled aircraft range: the fighter's effective reach is now 25 tiles and the bomber's 50, with missionRange raised to match.
- Political map country names were invisible because the label SVG had a zero-sized viewport, which some browsers never paint; size it to the world and guard it with a test.
- Added a Devlog button showing the ten latest commits, generated into client/js/devlog_data.js by scripts/generate-devlog.js and refreshed by the pre-commit hook.
- Worked through FIXME.md: the city button and a unit double-click now open the city, and the stat tooltip escapes the HUD so the unit panel cannot cover it.
- The server creates its game at startup and clients only join it; the Create game screen and the configure_game path are gone, and testing is a --testing server flag.
- A page on a loopback host signs in as adrien, claims France and gets the free, instant testing buttons, while the server grants free orders only to a loopback socket whose Origin is also loopback.
GDP per capita had no natural growth, so a nation's economy only moved
when population, buildings or war did. The summary stats also offered
inconsistent hover text: a native browser tooltip for popularity and none
at all for the budget.
- Every land tile now gains a constant 0.01% of the GDP per capita it
opened with, once a day. Because the amount is fixed the relative growth
rate tapers over the years. Each tile's opening figure is snapshotted
once and shipped to the browser, so the tile panel and the GDP-per-capita
map mode stay in step with the server.
- The population, GDP and GDP/capita tooltips show the relative growth:
against 1 January 2000 through the first year, then year on year. The
monthly captures now keep a rolling thirteen months for the baseline.
- Every summary stat explains itself through the same custom bubble.
Popularity's native title moved onto it, and Budget forecasts the next
calendar month at the current hourly net, as a compact figure such as
"+€3.28B/mo" (hoursInNextMonth follows the real calendar).
- The tile GDP breakdown shows gains with a plus sign (natural growth,
ports) rather than the old minus.
Added tests for the constant daily gain, the falling relative rate, the
first-year and year-on-year baselines, the snapshot baseline, the budget
forecast and the calendar month length.
A country's name is fitted to the shape of its holding without ever
squashing the letters, so a large holding with a short name ran out of
kerning before it filled the space.
- Raised MAX_KERNING from 2 to 5, letting the run open up further across
broad holdings.
- Noted at the top of the file that these figures are meant to be tuned by
hand and must not change how the tests behave.
The catalogue had grown a barracks, wartime shelters, an air-defense
battery, a warm-water port and a shipyard, but only as data: infantry
still trained without a barracks, shelters did nothing, and an airport was
just an airbase. Each building now names the rule it grants with a
`mechanic` id, so the simulation and the city panel describe the same
thing without magic strings.
- Barracks and shipyards open one more production line each. A line sticks
to one entry at full rate, so two units build at once rather than the
head absorbing every line; the base behaviour (one queue, overflow
carrying into the next entry) is unchanged.
- Wartime shelters keep 10% of civilians per level safe from bombardment
and are very hard to knock down, and ranged fire can now destroy a
building level outright, with no refund. Each building rolls its own
chance per point of damage, from a generator seeded off the world so a
bombardment replays identically.
- Air defense fires one volley at a hostile aircraft the moment it enters
the city tile, scaled by its level; a plane shot down never drops its
bombs.
- A port adds 1000 GDP per capita per level, per adjacent sea tile, to
every tile in its region.
- An airport draws a daily trickle of people from every other airport city
in the world, scaled by the destination's level.
- Wired the new effects into the city panel and taught the repeatable
Industrial Automation to satisfy other technologies' prerequisites.
Added tests for each mechanic and for the parallel lines.
Marching into enemy territory changes visibility every step, and each change
rebuilt the whole on-screen fog band. A tile's fog depends only on its own
level and its six neighbours', so the exact dependency radius is one tile, far
tighter than the vision radius.
- Every tile owns a fixed slot in one fog buffer, so rebuilding a tile never
shifts another's vertices and only the touched row spans are re-uploaded.
_applyKnowledge now diffs the visible/explored sets and hands the renderer
the changed tiles; buildFogTiles rebuilds them with their rings. On a 100x100
map a frontier patch is ~3-4 ms against ~80 ms for the band.
- A pan that leaves the built rows now builds only the newly exposed rows, and
the escape margin scales with the viewport, so dragging rebuilds rarely.
- _frame schedules the next animation frame before doing any work and catches
an error, so a one-off failure can no longer stop the frame loop for good.
- Added tests for the per-tile patch and the incremental pan.
Marching into unexplored or enemy land reveals a tile every step, and each
reveal rebuilt the whole-map fog mesh: about 1.8M vertices and 50 MB on a
160x160 map, regenerated at the rebuild throttle. Walking through
already-explored home land reveals nothing, which is why the stutter only
showed up on a border crossing, with a single unit.
- buildKnowledge now takes a row range and builds only the rows on screen; the
row table stays full length so the existing row-banded draw keeps working.
- _flushFog rebuilds on a visibility change or a pan to a new row band, still
coalesced, and the draw clamps to the band that was built.
- A mode/zoom change schedules the band rebuild instead of building the whole
mesh, and uniform interior tiles skip the per-vertex blur kernel.
- The bombardment overlay was rebuilt every animation frame, and each barrage
scanned the whole army to find its target (O(strikes x units)). It now
redraws at most at the renderer's 24 fps, reuses its SVG/DOM nodes, and
resolves garrisons from one per-snapshot tile index, so a high-refresh
display no longer makes a big battle worse.
- Route truncation had the same shape: every step of every route rescanned
every unit. The snapshot now buckets the army by tile once.
- Idle units no longer have identical left/top rewritten every frame, and the
whole-map fog buffer is rebuilt less often.
- Snapshot traffic: cityStats and visible are delta-encoded like territory and
population, city stats carry a content-hash version, tile ethnicity is
memoised, and a city's economy is derived once per broadcast instead of
twice. A per-peer civ change now forces a full snapshot, since the visible
set is per-viewer.
- Tile improvements (fortifications, radar towers, coastal cannons), trenches,
zone of control, support-unit capture and launch transports, with parabolic
barrage arcs drawn between attacker and target.
- Focused research that pours points straight into the chosen technology, with
per-technology progress kept when the focus changes, plus repeatable levels.
- Popularity reworked to integer points, war and pillage effects, minority
policies and month-over-month arrows on the nation summary.
- City progress bars, square improvement buttons, a technology tab of wide
short cards with progress bars, transport cargo readout and double-click to
open a city panel.
- the nation summary shows own-government approval, white in the neutral 40-60% band, red below and green above
- the city and government panels keep a fixed size per tab, dock below the summary and no longer cover it, and their tab bar wraps instead of being clipped
- propaganda campaigns grow exponentially harder near their opinion ceiling or floor, so the last percent are the hardest to win
- memoised city, nation and matrix approval against the politics version, invalidated by territory redraws, so snapshots stop recomputing it every frame
- extracted the duplicated modal tab wiring into modals/tabs.js
- tests: campaign-difficulty, approval-colour and cache-invalidation cases (513 pass)
- a strike is accepted only when the whole round trip (out to the target, then
home to a friendly airport) fits the remaining fuel, and the browser mirrors
the check so an unreachable target is refused with its distance and the
plane's effective range
- a bomber that bombs between hourly ticks turns for home at once instead of
idling and crashing on an empty tank; a plane with a runway lands on fumes
- aircraft may now target a garrison inside a hostile city: they bomb it and
turn away, and captures skip aircraft so the city is never taken
- bomber/jet endurance and mission-range tuning
- aircraft attack orders fly a sortie to the target, bomb once, return to a
friendly airport and re-arm (two-day cooldown, charged per aircraft); rebasing
is bounded by fuel rather than the 10-tile combat radius
- artillery and warships open a sustained hourly bombardment on a standing
target, drawn as a red dashed line and ring while either endpoint is selected
- a game launched from localhost can enable a testing mode whose train and build
rows offer free, instant orders; the server only honours them for a loopback
admin in a testing game
- an open city panel now unlocks aircraft as soon as an airport finishes
- run_tests.js discovers and runs each *_test.js in its own worker process
(--jobs N to cap the pool, --file <name> for a single suite)
- GameState caches the deterministic terrain, city sites and road network by
(seed, mapConfig, civ count), rebuilding only the mutable per-game state
- the snapshot ships mapConfig and the client rebuilds terrain from it, so the
DOM tests can use the small map fixture and a non-default config renders right
- shortestPaths can stop once every target city is settled
Roads are pre-generated between cities with a greedy geometric spanner and flatten unit movement cost. City improvements now only affect the tiles their region controls, with per-region tax collection and a Cities tab. The budget is a grouped, scrollable table with 25%/year tax and a 10%-of-GDP opening treasury. Also merged the tile info into the city panel, kept conflict and budget expansion state across snapshots, added join notifications, filled border corners, drew battle sides as stacks and made tab overflow scroll.