Store defended influence in defendedStrengthTexture and sample it in territory render shader
Recompute defended strength on tick for state-updated tiles and for post-change dirty tiles, with full-map fallback when diffs are large
Pack defense posts by owner on GPU (owner offsets + posts buffer)
Remove old defended clear/update passes and epoch-based params
Replace epoch-based defended texture tracking with hard-clear approach for
improved reliability and performance. Remove complex dirty state tracking
and epoch incrementing logic in favor of direct hard clears before rebuilds.
Changes:
- Remove wasDefensePostsDirty tracking from TerritoryRenderer
- Replace numUpdates > 0 checks with hasStateUpdates boolean
- Hard-clear defended texture before restamping instead of epoch management
- Mark DefendedUpdatePass as dirty when rebuilding defended state
- Rebuild bind group in DefendedUpdatePass when missing, not just on buffer change
This eliminates potential transient mismatches where defended rendering
disappeared between rebuilds and simplifies the update pipeline.
Replaced tile sampling for terrain colors with direct extraction from the theme object, significantly improving performance. Updated shore, water, shoreline water, plains, highland, and mountain color computations to utilize theme properties, eliminating the need for tile searches. This change enhances efficiency in terrain color management while maintaining visual fidelity.
Modified the workgroup size in the state-update compute shader from 1 to 64 for improved parallel processing. Adjusted the dispatch logic in StateUpdatePass to calculate the correct number of workgroups based on the new size, enhancing performance during state updates. Removed unnecessary terrain parameter upload in TerritoryRenderer to streamline resource management.
Updated the terrain recomputation logic to trigger asynchronously, improving performance by allowing rendering to continue without blocking. This change ensures that the terrain will be ready for the next frame, which may result in displaying stale terrain for one frame but enhances overall rendering efficiency.
Refactor the monolithic TerritoryWebGLRenderer into a modular, extensible
architecture that separates ground truth computation from rendering passes.
This change also includes related improvements to game state management and
hover information handling.
WebGPU Architecture Refactor:
- Extract all shaders to external .wgsl files (no inlined shaders)
- Separate ground truth data management (GroundTruthData) from rendering
- Create pass-based architecture with ComputePass and RenderPass interfaces
- Implement compute passes: StateUpdatePass, DefendedClearPass, DefendedUpdatePass
- Implement render pass: TerritoryRenderPass
- Add TerritoryRenderer orchestrator with dependency-based execution ordering
- Add WebGPUDevice for device initialization and management
- Add ShaderLoader utility for loading .wgsl files via Vite ?raw imports
Performance Optimizations:
- Dependency order computed once at init (topological sort)
- Early exit checks at orchestrator and pass levels
- Bind groups rebuilt when textures/buffers are recreated
- Zero per-frame allocations (reuse command encoders and staging buffers)
Architecture Benefits:
- Easy to extend with new compute/render passes (borders, temporal smoothing, etc.)
- Clear separation between tick-based compute and frame-based rendering
- All shaders in external files for better maintainability
- Ground truth data computed once and reused by all passes
Related Changes:
- Add defended tile state support to GameMap (isDefended/setDefended)
- Expose tileStateView() for direct GPU state access
- Extract hover info logic to HoverInfo utility
- Remove TerrainLayer (terrain now rendered by WebGPU territory pass)
- Update GameRenderer to use transparent overlay canvas
- Add viewOffset() method to TransformHandler
Files:
- Deleted: TerritoryWebGLRenderer.ts (1217 lines), TerrainLayer.ts (77 lines)
- Added: 17 new files in webgpu/ directory structure
- Updated: TerritoryLayer.ts, GameRenderer.ts, PlayerInfoOverlay.ts,
GameMap.ts, GameView.ts, GameImpl.ts, TransformHandler.ts, vite-env.d.ts
Resolves#2718
## Description:
Adds go-style error log levels, with an additional ALL log level.
- WARN/ERROR - Only success output
- INFO - Existing output
- DEBUG - New output
- ALL - New output (includes the logs from when removal/performance is
enabled)
In addition
- Add `-verbose` (`-v`), `-log-level`, `-log-removal`, and
`-log-performance` flags to map generator
- No changes to default behavior of `go run .` without the new flags
- excludes test maps from performance warnings (test maps already skip
the removal steps)
- updates readme with the different flags and how they impact the logger
Default run (matches existing)
`go run . >> output.txt 2>&1`
[output.txt](https://github.com/user-attachments/files/24365745/output.txt)
Default run w/ `-verbose` (log level DEBUG)
`go run . -v >> output.txt 2>&1`
[output.txt](https://github.com/user-attachments/files/24365812/output.txt)
Default run w/ `-log-performance`
`go run . -log-performance >> output.txt 2>&1`
[output.txt](https://github.com/user-attachments/files/24365971/output.txt)
Run of just africa w/ all new logging enabled
`go run . -maps=africa -log-level=all >> output.txt 2>&1`
[output.txt](https://github.com/user-attachments/files/24365724/output.txt)
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
tidwell
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Reverts openfrontio/OpenFrontIO#2911
## Description:
Reverts confusing "billion"
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves#2704
## Description:
Merges together easy + medium difficulties.
Before:
<img width="1500" height="580" alt="image"
src="https://github.com/user-attachments/assets/26199d52-8ef2-4feb-ae87-bbfff35e3115"
/>
After:
(dont have one to show oop)
(btw that win ratio in the first screenshot is not mine.. 💀)
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves [#2910](https://github.com/openfrontio/OpenFrontIO/issues/2910)
## Description:
When any number is rendered using the Utils.ts renderNumber() function
that is greater than 999,999,999, the display uses 1001M instead of 1B.
Similar to existing logic, I expand the if statements to check if the
number is greater than a threshold in the billions, and format it
accordingly if so.
Screenshots:
<img width="1268" height="370" alt="image"
src="https://github.com/user-attachments/assets/e4edf28b-94bd-4ec6-a4e6-083b9a2fd4fb"
/>
<img width="271" height="238" alt="img1"
src="https://github.com/user-attachments/assets/bc259f4d-68e8-4b6a-831b-34f02cf56750"
/>
## Please complete the following:
- [YES] I have added screenshots for all UI updates
- [YES ] I process any text displayed to the user through
translateText() and I've added it to the en.json file
- [YES] I have added relevant tests to the test directory
- [YES] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
visneh
## Description:
mls for v29
Version identifier within MLS: 4.13
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
aotumuri
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves#2889
## Description:
fixes login in modal:
<img width="782" height="330" alt="image"
src="https://github.com/user-attachments/assets/60f1825f-5678-4853-a78b-bbed5198b0fb"
/>
(theres also one more afterwards but that leaks my email and cba to edit
it out)
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves#2868
## Description:
This PR addresses a critical memory leak in the Master server process
(causing ~30GB RAM usage).
The issue was caused by `setInterval` calling `fetchLobbies()` every
100ms. When `fetchLobbies` took longer than 100ms to complete (due to
network latency or load), requests would pile up indefinitely, creating
a massive queue of pending Promises and open sockets.
I have refactored the polling logic into a generic `startPolling`
utility (in `src/server/PollingLoop.ts`) that uses a recursive
`setTimeout` pattern. This ensures that the next `fetchLobbies` call is
only scheduled *after* the previous one has completed (successfully or
failed), preventing any request pile-up.
## Please complete the following:
- [x] I have added screenshots for all UI updates (N/A - backend only)
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file (N/A - no user facing text)
- [x] I have added relevant tests to the test directory
(`tests/PollingLoop.test.ts`)
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
codimo
## Description:
The recent pathfinding rework broke the naval invasion target.
This change reverts the code to the previous working one.
<img width="232" height="273" alt="image"
src="https://github.com/user-attachments/assets/0cc3ed80-bd77-4e7b-886b-0ce5012840ac"
/>
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
IngloriousTom
## Description:
Bots always attacked Terra Nullius if they shared a border with Terra
Nullius.
But water is Terra Nullius...
So I changed that condition to `this.bot.neighbors().some((n) =>
!n.isPlayer())`.
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
FloPinguin
Been playing this game for months, and after i feel myself enough
experienced about the game, decided to start contributing to the
project. This is my first one!
## Description:
Move indicator fx for warships. Listening MoveWarshipIntentEvent to draw
the fx. Code is basic, respectly layered and written regarding project's
structure.

## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
420coder
---------
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
## Description:
* Add RankedType enum, for now it's just 1v1
* Add new method to MapPlaylist to create 1v1 game config
* Update WinCheck so the last player is declared a winner on 1v1.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
evan
## Description:
Changes URL embeds within other platforms, e.g. Discord, WhatsApp & X.
Updates game URLs to `/game/<code>` instead of `/#join=<code>` (required
for embedded URLs). An added benefit of this is that you would be able
to change a url from `openfront.io/game/RQDUy8nP?replay` to
`api.openfront.io/game/RQDUy8nP?replay` (add api. In front) and be in
the right place for the API data.
Updates URLs when joining/leaving private lobbies
Appends a random string to the end of the URL when inside a private
lobby and options change - this is to force discord to update the
embedded details.
Updates URL in different game states to ?lobby / ?live and ?replay.
These do nothing other than being used as a _cache-busting_ solution.
-----------------------------------------------
### **Lobby Info**
Discord:
<img width="556" height="487" alt="image"
src="https://github.com/user-attachments/assets/efd4a06d-506c-4036-9403-ee7c9a669e21"
/>
WhatsApp:
<img width="353" height="339" alt="image"
src="https://github.com/user-attachments/assets/3b2d0c69-988c-424f-9dee-f4e6a6868f6b"
/>
x.com:
<img width="588" height="325" alt="image"
src="https://github.com/user-attachments/assets/d9e78169-20be-4a3e-8df4-8ad41d08a750"
/>
-------------------------
### **Game Win Details**
Discord:
<img width="506" height="468" alt="image"
src="https://github.com/user-attachments/assets/69947774-c943-4a50-b470-5634ed3bf3d7"
/>
WhatsApp:
<img width="770" height="132" alt="image"
src="https://github.com/user-attachments/assets/eec28bf8-bf64-4ab8-954e-03dfdd1aae40"
/>
x.com
<img width="584" height="350" alt="image"
src="https://github.com/user-attachments/assets/168063e2-b707-422b-b7a1-0025f3ebeb92"
/>
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
## Description:
The current gold stats don’t include gold generated by trains, even
though this is a significant part of the economy for many players.
This PR tracks those stats with two values:
- other players trains visits the player station
- the player trains visits any station
Linked to this infra PR: https://github.com/openfrontio/infra/pull/242
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
IngloriousTom
## Description:
Should fix the broken 1v1 on staging. The issue was that we had multiple
staging environments, and the matchmaker would often route a player to a
game on a different staging server, so the client couldn't find the
game.
So now each deployment has a unique id, and the matchmaker only connects
players & servers that have the same instance id.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
evan
# Pathfinding pt. 3
## Description:
This PR introduces final change to the pathfinding - path refinement. It
optimizes Line of Sight refinement by searching with for the best tile
with a binary search instead of linearly. And then spends the recovered
budget on better refinement of the first and last 50 tiles of the
journey - the place where user is most likely to look at. Additionally
this PR re-introduces magnitude check and makes the ships prefer sailing
close to the coast, but not too close.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## What?
| Before | After |
| :--- | :--- |
| <img width="1097" height="1117" alt="image"
src="https://github.com/user-attachments/assets/4a0b300d-10ef-4151-b6dc-33acfb49f992"
/> | <img width="1093" height="1119" alt="image"
src="https://github.com/user-attachments/assets/cf81c515-c145-40f4-91e5-a4353986907b"
/> |
| <img width="1096" height="1129" alt="image"
src="https://github.com/user-attachments/assets/21b46bce-f961-4259-88f6-fe4a66180270"
/> | <img width="1098" height="1126" alt="image"
src="https://github.com/user-attachments/assets/d92587d1-e6b6-4353-b4a4-1efe71bca43d"
/> |
## Performance
There is actually a severe performance impact of these changes. The path
initial path takes almost 2x as long to generate - this is because pre
processing can only do so much if the initial path is ugly. Luckily in
real gameplay we only need to do this calculation once per edge, so the
actual observed performance impact should be much smaller. Cache FTW.
| | No Cache | Cache |
| :--- | :--- | :--- |
| Before | 277.04ms | 208.58ms |
| After | 498.34ms | 264.27ms |
## DebugSpan
Small utility, it allows any code to be easily instrumented for
performance. The idea is the same as with [OTEL
Spans](https://opentelemetry.io/docs/concepts/signals/traces/). Produce
a span, create sub-spans, measure whatever you need. Works only when
`globalThis.__DEBUG_SPAN_ENABLED__ === true`, otherwise no-op.
Cool stuff, try it out:
```ts
// Convenient wrapper, small performance impact
return DebugSpan.wrap('add', () => a + b)
// Synchronous API, basically free
DebugSpan.start('work')
work()
DebugSpan.end()
// Create sub spans
DebugSpan.wrap('complex', () => {
const aPlusB = DebugSpan.wrap('add', () => a + b)
DebugSpan.set('additionResult', () => aPlusB) // Store data
return aPlusB * c
})
// Access spans, data and timing
const span = DebugSpan.getLast()
const compelxSpan = DebugSpan.getLast('complex')
console.log(complexSpan.duration, complexSpan.data['additionResult'])
```
These are virtually free and can be enabled on-demand **in production**
and available in the devtools. Under the hood devtools integration is
just a wrapper around [Performance
API](https://developer.mozilla.org/en-US/docs/Web/API/Performance_API).
For clarity data keys not prefixed by `$` are omitted from the
integration. Every key prefixed with `$` must be fully JSON
serializable.
<img width="977" height="799" alt="image"
src="https://github.com/user-attachments/assets/b4d43506-1639-4f78-a611-30e61de12a07"
/>
## Description:
Doesn't need a description :D
https://github.com/user-attachments/assets/8de576fd-050b-4b35-8526-e4c88d1a9f25https://github.com/user-attachments/assets/c99147a1-efdf-426b-96d1-e996e01f89aa
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
FloPinguin
## Description:
fix(ui): add missing dark variant to styles.css
Before:
<img width="549" height="77" alt="image"
src="https://github.com/user-attachments/assets/d7c2bf92-691b-473c-880a-da678eb792a3"
/>
After:
<img width="555" height="84" alt="image"
src="https://github.com/user-attachments/assets/a2c828db-7fea-409a-abdd-fefc0dc237f0"
/>
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
wraith4081
---------
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
## Description:
This PR makes several existing keybinds configurable that were
previously fixed and could not be changed in the keybind settings.
This is one of the required PRs to fully remove all keybind explanations
from the HelpModal.
This work is based on the following feedback by @ryanbarlow97:
> "This probably needs to be redone / removed from help, and just have a
section saying how to get to the keybinds modal inside settings"
>
https://github.com/openfrontio/OpenFrontIO/pull/2872#issuecomment-3740006017
Some keybinds described in the HelpModal already existed internally, but
users had no way to change them.
By making these keybinds configurable, we can now safely replace those
explanations with a simple reference to the keybind settings instead.
This helps:
- Remove keybind explanations from the HelpModal
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
aotumuri
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
## Description:
There was a mismatch between the Lemnos map settings in the `info.json`
and the what was in the resources folder. I regenerated the map using
the map-generator to make sure the latest changes were applied.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
bijx
## Description:
The calculation is based on: 50 players per 1_000_000 land tiles,
limited at 125 players because of performance
Second number is 75% of that, third one 50%
That way, the player counts are staying mostly the same
Look at the "Dynamic Config" column, these are the new player counts:
(The 125 players limit is missing in that column, only relevant for the
twolakes map)
<img width="930" height="1033" alt="Screenshot_2026-01-12_152758"
src="https://github.com/user-attachments/assets/e1791740-e263-47b3-8b27-4f9aa358d381"
/>
<img width="926" height="324" alt="Screenshot_2026-01-12_152814"
src="https://github.com/user-attachments/assets/78d6789b-374f-4f8b-b50f-f6f08395572b"
/>
This PR also removes `MapDescription` from `Maps.ts` because its unused.
And this PR updates the map-generator `README.md` to reflect the changes
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
FloPinguin
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #(issue number)
## Description:
Moved the Modal Headers into its own class
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
## Description:
<img width="982" height="1086" alt="image"
src="https://github.com/user-attachments/assets/fb97f2e2-0e1a-4e21-baad-3e8cbd81624b"
/>
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
FloPinguin
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #(issue number)
## Description:
Remove borders from some elements
**Tailwind changes only**
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #(issue number)
## Description:
remove the colours from the shop modal, also small tweak to header bar
in instructions
**Only Tailwind Changes**
<img width="843" height="209" alt="image"
src="https://github.com/user-attachments/assets/1f99aa8d-8756-4b70-9ff0-6495d5eb48bf"
/>
<img width="841" height="183" alt="image"
src="https://github.com/user-attachments/assets/ac40ed0d-7588-4336-b3d1-ce4be5f8a312"
/>
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
## Description:
fix url
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
## Playtest
https://pf-pt-2.openfront.dev/
## Pathfinding Refactor pt. 2
<img width="1536" height="1024" alt="image"
src="https://github.com/user-attachments/assets/9477958e-54b7-4c83-b317-ba789e809e9e"
/>
This is a follow-up to a previous PR introducing pathfinding changes.
This time, it introduces a complete refactor of `pathfinding` directory
and breakdown into composable pieces.
### Unified PathFinder interface
`PathFinder<T>` and `SteppingPathFinder<T>` are introduced to unify
**all** pathfinding across the application. First one exposes complete
path, while stepping variant allows the callee to iterate over the path
by calling `.next`. All pathfinders share this one common interface,
which makes them easy to use in any scenario -
`PathFinding.Water(game).search(from, to)`.
`SteppingPathFinder<T>` extends `PathFinder<T>` with an ability to
iterate over the path. It handles caching, storing current index and
invalidation. This allows the units to not care about the inner workings
of the pathfinder and just call `pf.next(current, target)` and receive
instructions on what to do next.
### Common entry point
All pathfinders are now exposed from common `PathFinding` entrypoint:
- `PathFinding.Water`
- `PathFinding.Rail`
- `PathFinding.Stations`
- `PathFinding.Rail`
Additional entry point is introduced for pathfinders which need to work
both in the worker, but also on the frontend, which lacks `Game`
interface. Currently only `UniversalPathFinding.Parabola` is available.
### Spatial Query
New module has been introduced close to `pathfinding` - `SpatialQuery`.
It aims to resolve any questions game may have about finding tiles
meeting criteria. Currently `SpatialQuery.closestShore(player, target)`
and `SpatialQuery.closestShoreByWater(player, target)` are available -
they help answering questions about naval invasion: "What is the best
landing location from user's click?" and "Which our tile should be used
to launch the transport ship?". Under the hood they use very similar
mechanics to pathfinding, so it felt right to put them close by.
### Modular architecture
Pathfinders now support transformers: `MiniMapTransformer`,
`ShoreCoercingTransformer`, `ComponentCheckTransformer`,
`SmoothingTransformer`. Transformers functions like a middleware in the
pathfinding chain. They wrap around the pathfinder and provide
additional functionality. This allows the pathfinder to focus on
actually finding the path instead of doing unrelated things.
Example chain for simple (A*) water pathfinding:
```ts
static WaterSimple(game: Game): SteppingPathFinder<TileRef> {
const miniMap = game.miniMap();
const pf = new AStarWater(miniMap);
return PathFinderBuilder.create(pf)
.wrap((pf) => new ShoreCoercingTransformer(pf, miniMap))
.wrap((pf) => new MiniMapTransformer(pf, game.map(), miniMap))
.buildWithStepper(tileStepperConfig(game));
}
```
The Pathfinder - here `AStarWater` - does not care about the conversion
between minimap and main map tiles. It also does not care if the source
or destination is a land tile. The transformers take care of that. The
pathfinder gets a set of valid coordinates and produces the path -
that's it.
Modular approach makes working on a particular set of utilities much
easier - for example map upscaling is handled consistently across all
pathfinders. Additionally, the pathfinders are not tied to the
particular map resolution used. Pass them a different map and they will
work the same.
### Algorithms
Algorithms used are neatly organized inside
`src/core/pathfinding/algorithms`. They are prefixed with the algorithm
name and suffixed with the use case. File without suffix exposes generic
version ready to traverse any graph with adapters. Specialized versions
either use an adapter or inline logic when performance is critical -
using adapters leads to 20-30% performance loss.
The directory includes `A*` and `BFS` but also other useful utils, such
as `AbstractGraph` used to generate... an abstract graph on top of the
tile map and `ConnectedComponents` helping to identify whether two tiles
are connected by a path without actually computing the path.
### Playground
The playground have been updated with new algorithms, including tweaked
very greedy `A*`.
<img width="2175" height="1424" alt="image"
src="https://github.com/user-attachments/assets/1f833651-0024-4299-bf86-882f5368358c"
/>
### Tests
Yeah, there are some, a little too many if I say so myself. But there
are no useless tests. I had to ensure refactored code works somehow
reliably. This PR comes with trust me bro guarantee, but I would
appreciate someone confirming **naval invasions, nukes (esp. MIRV) and
warships**.
### Discord
`moleole`
GL & HF
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves
https://discord.com/channels/1330359017247346812/1330365278420471911/1358027146139795486
## Description:
In HelpModal, only the TargetIcon was displayed in red, which was
inconsistent with the other icons.
This PR updates its color to white so it matches the rest of the icons.
before
<img width="397" height="458" alt="スクリーンショット 2026-01-11 22 24 54"
src="https://github.com/user-attachments/assets/2a2f5aa0-a31c-4ecb-887e-f151689c3236"
/>
after
<img width="370" height="438" alt="スクリーンショット 2026-01-11 22 25 08"
src="https://github.com/user-attachments/assets/d0c74805-8bc8-4e94-8a18-23488aba0389"
/>
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
aotumuri
Co-authored-by: FloPinguin <25036848+FloPinguin@users.noreply.github.com>
## Description:
UI Refinements requested by @evanpelle check https://ui.openfront.dev
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
w.o.n
Resolves
https://discord.com/channels/1359946986937258015/1458658371891761339/1459478370977972316
## Description:
The play-like icon on the left side of the Recent Games UI looked
clickable but did not actually start a replay, which could be
misleading.
This PR updates the behavior so that clicking the icon now starts the
replay, matching the visual affordance and reducing user confusion.
https://github.com/user-attachments/assets/db9f02d9-9492-47ba-948b-6a6e0166d4d3
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
aotumuri
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
Co-authored-by: iamlewis <lewismmmm@gmail.com>
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves#1225
## Description:
Replace all raw displayMessage strings with events_display.* keys +
params and add the new English translations in resources/
lang/en.json so EventsDisplay can translate them.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
aotumuri
---------
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
## Description:
Fixed map assets and generated outputs. Fixed issues with map not
loading and pathfinding not working. Britannia (new) and Britannia
Classic. Now work correctly.
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
Tsprophet
---------
Co-authored-by: Harry <Harry.bath94@gmail.com>
Co-authored-by: iamlewis <lewismmmm@gmail.com>
## Description:
Fixed a bug that prevented debug mode from working.
Made it so that parameters are displayed.
<img width="800" height="559" alt="スクリーンショット 2026-01-10 14 24 51"
src="https://github.com/user-attachments/assets/2eff3073-15fe-4879-9448-c7f20b5e4eab"
/>
translation-key::parameters
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
aotumuri
## Description:
Didier map name had a little UI problem.
And unrelated change: Because Lewis today said "it should be super low"
I turned down the frequency of this map from 2 to 1.
Previous:
<img width="1916" height="1312" alt="image2"
src="https://github.com/user-attachments/assets/0a84160b-91a8-4d02-b707-fa9eea1a15fd"
/>
Fixed:
<img width="562" height="476" alt="image"
src="https://github.com/user-attachments/assets/31fed7b5-c128-45cd-a63d-0aab3345cea3"
/>
## Please complete the following:
- [X] I have added screenshots for all UI updates
- [X] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [X] I have added relevant tests to the test directory
- [X] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
FloPinguin
## Description:
In HelpModal, only the BoatIcon was displayed in black, which was
inconsistent with the other icons.
This PR updates its color to white so it matches the rest of the icons.
before
<img width="619" height="235" alt="スクリーンショット 2026-01-10 14 33 44"
src="https://github.com/user-attachments/assets/41c10308-7701-40bf-b068-9e14eb78a83a"
/>
after
<img width="722" height="260" alt="スクリーンショット 2026-01-10 14 35 17"
src="https://github.com/user-attachments/assets/2d535ded-83d2-4f3d-990d-49aaa1230642"
/>
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
aotumuri
Resolves#2652#2291
## Description:
Resolves a regression after a new design changes where keybinds
explicitly set to "Null" were incorrectly reverted to default values
instead of remaining unbound.
Updates the input handler to preserve "Null" as the designated value for
an unbound key. The UI now reflects this by displaying "None" for
keybinds that are set to "Null", providing clear user feedback.
Before/After:
<img width="378" height="371" alt="image"
src="https://github.com/user-attachments/assets/d1d640f2-93aa-47f1-be8e-7d8c68183aa1"
/> <img width="379" height="370" alt="image"
src="https://github.com/user-attachments/assets/f0512cce-c6e9-4180-9517-7669aed76f6f"
/>
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
webdev.js
Co-authored-by: antigrid <Stepan.Hembarovskyi@Inu.edu.ua>
## Description:
Removes code duplication by consolidating the `formatPercentage` utility
function to the `Utils.ts` file, removing the two identical
implementations in `TeamStats.ts` and `Leaderboard.ts`.
This is an improvement upon #2838 which is the PR that aligned the two
mentioned implementations.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
## Please put your Discord username so you can be contacted if a bug or
regression is found:
deshack_82603