- Introduced WorkerMetricsEvent and SetWorkerDebugEvent to facilitate communication between the main thread and worker for performance monitoring.
- Enhanced ClientGameRunner to emit worker metrics and handle debug configuration updates.
- Updated PerformanceOverlay to display worker metrics and allow toggling of debug settings.
- Refactored Canvas2DRendererProxy and TerritoryRendererProxy to improve rendering performance and manage render cooldowns.
- Added profiling capabilities in Worker.worker.ts to track event loop lag, simulation delays, and message handling metrics.
- Add render_done worker message and tag render_frame with an id.
- Gate TerritoryRendererProxy/Canvas2DRendererProxy to one in-flight render (2s safety timeout) to prevent render queue buildup.
- Split roster vs palette dirtiness in GameViewAdapter and only force full relations rebuilds on roster/team changes.
- Only markRelationsDirty() on roster changes in WorkerTerritoryRenderer to avoid repeated expensive uploadRelations() while paused.
- GameViewAdapter: build from tileState/terrainData buffers and game
updates (players, defense posts, embargo/alliance) instead of Game +
TerrainMapData; add DefensePostUnit/PlayerLiteView and drop config().
- Worker: keep local renderTileState; tileUpdateSink receives packed
bigint and updates buffer + dirty queue; no terrain map load in worker.
- Proxies: send view size/transform only when changed, inline in
render_frame (optional viewSize/viewTransform); remove separate
set_view_size/set_view_transform messages.
- Simulation: remove main-thread RAF heartbeat loop; worker uses
scheduleSimPump() on heartbeat/addTurn to coalesce ticks.
- GroundTruthData: take defensePostRange at construction; Territory
renderer passes it through; remove runtime defensePostRange change check.
- GameRunner: tileUpdateSink(packedTileUpdate: bigint); add
hasPendingTurns().
- Introduced new properties and methods in GroundTruthData for handling relations, including `needsRelationsUpload`, `relationsDenseBySmallId`, and `pendingRelationsPairs`.
- Implemented logic to mark relations as dirty and upload relations conditionally based on changes in diplomacy.
- Updated Worker.worker.ts to synchronize relations updates with the renderer, optimizing performance by only refreshing when necessary.
- Enhanced WorkerTerritoryRenderer with methods to mark relations dirty, ensuring proper resource management during updates.
- Added support for terrain base RGBA values to optimize rendering.
- Refactored tile marking logic to utilize map dimensions for improved accuracy.
- Updated view size handling to prevent unnecessary canvas resizing.
- Introduced methods to rebuild terrain base and refresh terrain for better visual fidelity.
- Cleaned up initialization and cleanup processes for better resource management.
- Modified terrain shader parameters in GroundTruthData for better rendering.
- Added new user-configurable settings for water effects in TerrainShaderRegistry.
- Enhanced terrain compute shaders to incorporate water depth and blur adjustments.
- Refactored shader logic to improve water color blending and depth calculations
- Changed section title from "Shaders" to "Terrain" in WebGPUDebugOverlay.
- Updated default values for various terrain shader parameters to improve rendering quality, including noise strength, blend width, lighting strength, and cavity strength.
- Add terrain-compute-improved-lite.wgsl and terrain-compute-improved-heavy.wgsl
- Create TerrainShaderRegistry.ts for shader management
- Refactor TerrainComputePass to support dynamic shader switching
- Update TerritoryRenderer, TerritoryLayer, and GroundTruthData for new shader integration
- Enhance WebGPUDebugOverlay with additional debugging capabilities
- Introduced WebGPUComputeMetricsEvent to track compute timing.
- Added WebGPUDebugOverlay component for displaying WebGPU performance metrics.
- Refactored TerritoryLayer to utilize new shader management for territory rendering.
- Updated shaders to support new parameters for enhanced visual effects.
- Removed deprecated territory border mode settings from UserSettingModal and SettingsModal.
- Enhanced GroundTruthData to manage new textures for owner indices and relations.
- Improved shader parameter handling in TerritoryRenderer and related classes.
This commit enhances the WebGPU rendering pipeline, providing better performance insights and visual fidelity through improved shader management and debugging capabilities.
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
## Description:
move the width definition for PerformanceOverlay's layer bars into the
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:
wraith4081
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
## Description:
Fixes a trailing space in the attack ratio troop count.
**Before**
<img width="257" height="96" alt="Screenshot from 2026-01-19 20-36-57"
src="https://github.com/user-attachments/assets/0941c160-97dd-43a5-a111-cc3238ebbdb0"
/>
**After**
<img width="257" height="96" alt="Screenshot from 2026-01-19 20-29-45"
src="https://github.com/user-attachments/assets/cac06654-e13c-4831-a0f7-61ba1951338a"
/>
## 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:
n/a
## Description:
### Short path for multi-source HPA*
Math was not mathing, increased the bounds to 260x260, it is a bit
slower but should work better. The short path was breaking when player
owned a lot of shores. This is because the bounding box of tiles with
less than 120 distance + 10 padding could be as big as 260x260 and the
optimized array was set to 140x140. I made mistake of calculating it as
`2 * (60 + 10)` instead of `2 * (120 + 10)`.
### LoS path refinement
Previously, we ran 2 passes of LoS smoothing on the path. However, since
we are effectively tracing the same path, the line of sight is
essentially the same. This PR makes second line of sight stop on water
tiles with magnitude `n + 1` compared to first path. Practically, this
means it'll attempt LoS exactly 1 tile after previous corner. See
screenshot.
<img width="1299" height="1151" alt="image"
src="https://github.com/user-attachments/assets/726be236-1ff8-406c-896a-02902a762ab0"
/>
### SendBoatAttackIntentEvent
The flow of sending transport ships is currently strange. This PR makes
the flow more sane.
**Old flow**
```
- Player clicks TARGET tile, it can be deep inland
- Client asks Worker for the best START tile to TARGET tile
- Worker answers `false`, since the tile is inland
- Client sends BoatAttackIntent with START=false and TARGET tiles set
- Worker accepts BoatAttackIntent, computes DESTINATION as closest shore to TARGET
- Worker re-computes best START to DESTINATION
- Worker sends boat from START to DESTINATION
```
**New flow**
```
- Player clicks TARGET tile, it can be deep inland
- Client sends BoatAttackIntent with TARGET
- Worker accepts BoatAttackIntent, computes DESTINATION as closest shore to TARGET
- Worker computes START as the best tile to DESTINATION
- Worker sends boat from START to DESTINATION
```
## 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:
moleole
## Description:
Quickfix: Disable nations in ranked and change map selection
(Lewis wanted these, Australia three times so it occurs more often)
Just a quickfix, we will probably have to improve the map selection
later on, and maybe play on non-compact maps too?
## 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:
"You can pick your spawn in random spawn games in v29. You need to open
the menu and click on the attack button. That's it."
Thats the fix for this problem.
Radial menu no longer allows to attack (pick a spawn) while random spawn
is enabled.
And SpawnExecution got a check so you cannot send malicious intents.
## 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:
As reported on Discord, warship could get stuck. This PR fixes the
issue.
## 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:
moleole
## Description:
Fixes this little i18n problem:
<img width="732" height="172" alt="Screenshot 2026-01-16 050833"
src="https://github.com/user-attachments/assets/65fe27a6-f77a-49d9-94a9-145b4e719a88"
/>
## 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>
## Description:
Nuke trajectory prediction now will show interception with allied SAMs
if the alliance will break on nuke launch.
Code was also refactored to be shared a bit more.
In addition, if an incoming alliance would break if accepted, the nuke
launch will break the alliance.
<img width="1199" height="1002" alt="nukepr"
src="https://github.com/user-attachments/assets/c31066d9-66cf-4eaa-be3c-e2fbcfe7965a"
/>
## 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:
bibizu
## Description:
When a player is conquered (has less than 100 tiles left) their gold is
transfered to the conqueror. And after that the conqueror gets the last
tiles. But if some of those last tiles are not bordered by the
conqueror, they are given to their neighbour player. However that
neighbour player can be an ally. It is percieved as a bug if an ally
conquers/annexes tiles.
This PR fixes that by adding an isFriendly check to `handleDeadDefender`
in `AttackExecution`.
Now, there are already scenarios possible currently, where a player
survives being conquered. If they have some tiles on a small island for
example. Going from that, there should be no unexpected bugs following
this change. A player can be conquered twice in a game already in the
stats too.
https://discord.com/channels/1359946986937258015/1359946989046989063/1462595261204533248
Example of this happening in an Enzo vid (with his surprised reaction)
and explanation posted here:
https://discord.com/channels/1359946986937258015/1359946989046989063/1460483209308536925
## 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:
tryout33
## Description:
**Describe the PR.**
This PR improves how pathfinding finds a starting water tile when
launching a transport ship from a shore.
Previously, the code simply picked the first water neighbor it found.
This caused issues where, if a boat were traveling east, it might launch
out of a northern tile from a shore.
<img width="896" height="353" alt="image"
src="https://github.com/user-attachments/assets/69d83012-3397-43b3-8ab0-9ebde6ffea97"
/>
<img width="342" height="219" alt="image"
src="https://github.com/user-attachments/assets/a191f5cf-97da-4e34-a191-55ce14c794f0"
/>
The new logic checks all water neighbors and picks the "best" one by
counting how many water tiles surround it. This ensures transport ships
launch into the main body of water instead of suboptimal positions.
If two tiles have water neighbors with the same score, they are
tie-broken through a euclidean distance check.
## 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:
Scisyph
---------
Co-authored-by: WilliamT-byte <williamt2023@tamu.edu>
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
## Description:
This PR resolves a crash related to rail pathfinding reported on
Discord.
```
git checkout c179249cdd
npm run dev:staging
Replay id: kEbHPSP3
```
## 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:
moleole
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
## Description:
This PR resolves a crash related to rail pathfinding reported on
Discord.
```
git checkout c179249cdd
npm run dev:staging
Replay id: kEbHPSP3
```
## 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:
moleole
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
## Description:
**Describe the PR.**
This PR improves how pathfinding finds a starting water tile when
launching a transport ship from a shore.
Previously, the code simply picked the first water neighbor it found.
This caused issues where, if a boat were traveling east, it might launch
out of a northern tile from a shore.
<img width="896" height="353" alt="image"
src="https://github.com/user-attachments/assets/69d83012-3397-43b3-8ab0-9ebde6ffea97"
/>
<img width="342" height="219" alt="image"
src="https://github.com/user-attachments/assets/a191f5cf-97da-4e34-a191-55ce14c794f0"
/>
The new logic checks all water neighbors and picks the "best" one by
counting how many water tiles surround it. This ensures transport ships
launch into the main body of water instead of suboptimal positions.
If two tiles have water neighbors with the same score, they are
tie-broken through a euclidean distance check.
## 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:
Scisyph
---------
Co-authored-by: WilliamT-byte <williamt2023@tamu.edu>
Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
## Description:
If a WebSocket was "connecting", but the user un-clicks the lobby in
that time, it doesn't remove them from the lobby, and they would still
be put into the game.
@evanpelle needed for v29 imo.
It also fixes an issue where it wouldn't update your URL back to the
home url when unclicking the lobby (websocket issue or not).
This is a hotfix to fix that.
## 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:
Use `this.getEffectiveNationCount()` everywhere inside of
`LobbyPlayerView`, instead of `this.nationCount`. So the team player
counts always update properly.
## 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:
1. In JoinPrivateLobbyModal the nation count loading was missing. That
caused the team preview UI to show different player counts compared to
the HostLobbyModal. For example it showed 0/0 nations for the
HumansVsNations team mode (instead of 2/2):
<img width="726" height="217" alt="Screenshot 2026-01-16 211337"
src="https://github.com/user-attachments/assets/8b4219de-e2b2-46ff-a600-c86915e5bdb3"
/>
2. Turn down HvN difficulty from Impossible to Hard.
We steamrolled over Hard nations in the playtest (at least in two of the
three games) because we donated lots of troops to each other.
But after some API data research I noticed that only 33% of players in
public team games ever use the donate functionality.
And we probably have less skilled players in public games than in the
playtest.
So its probably better to use the Hard difficulty to ensure balanced
gameplay.
I know, I'm overthinking this 😂
## 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:
Extracted the CopyButton into its own component, and now reusing it in
"Account" too.
## 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:
Refactor / Clean-up code inside Host/Solo modals.
## 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: performance overlay positioning
## 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
## Description:
fix: performance overlay positioning
## 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
## Description:
Use `this.getEffectiveNationCount()` everywhere inside of
`LobbyPlayerView`, instead of `this.nationCount`. So the team player
counts always update properly.
## 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:
1. In JoinPrivateLobbyModal the nation count loading was missing. That
caused the team preview UI to show different player counts compared to
the HostLobbyModal. For example it showed 0/0 nations for the
HumansVsNations team mode (instead of 2/2):
<img width="726" height="217" alt="Screenshot 2026-01-16 211337"
src="https://github.com/user-attachments/assets/8b4219de-e2b2-46ff-a600-c86915e5bdb3"
/>
2. Turn down HvN difficulty from Impossible to Hard.
We steamrolled over Hard nations in the playtest (at least in two of the
three games) because we donated lots of troops to each other.
But after some API data research I noticed that only 33% of players in
public team games ever use the donate functionality.
And we probably have less skilled players in public games than in the
playtest.
So its probably better to use the Hard difficulty to ensure balanced
gameplay.
I know, I'm overthinking this 😂
## 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