Commit Graph

774 Commits

Author SHA1 Message Date
scamiv 09afa11a3e fix performance overlay 2025-12-11 17:17:58 +01:00
scamiv 0da975f615 add more stats to perf overlay 2025-12-11 17:17:56 +01:00
scamiv 2f2a12eefa Add performance metrics for worker and render ticks
- Introduced new metrics in ClientGameRunner to track worker simulation ticks and render tick calls per second.
- Updated TickMetricsEvent to include these new metrics.
- Enhanced PerformanceOverlay to display worker and render ticks per second, improving performance monitoring capabilities.
- Adjusted minimum FPS in GameRenderer
2025-12-11 17:17:53 +01:00
scamiv 2dde26223c add "ticks per render" metric 2025-12-11 17:17:52 +01:00
scamiv 0ffe9c39ad remove redundant logic 2025-12-11 17:17:51 +01:00
scamiv f710c78dcf Clean up previous implementations
removed:
- catchUpMode and its CATCH_UP_ENTER/EXIT thresholds in ClientGameRunner
- tick metrics fields and overlay UI for inCatchUpMode and beatsPerFrame
- leftover worker heartbeat plumbing (message type + WorkerClient.sendHeartbeat) that was no longer used after self-clocking

changed:
- backlog tracking: keep serverTurnHighWater / lastProcessedTick / backlogTurns, but simplify it to just compute backlog and a backlogGrowing flag instead of driving a dedicated catch-up mode
- frame skip: adaptRenderFrequency now only increases renderEveryN when backlog > 0 and still growing; when backlog is stable/shrinking or zero, it decays renderEveryN back toward 1
- render loop: uses the backlog-aware renderEveryN unconditionally (no catch-up flag), and resets skipping completely when backlog reaches 0
- metrics/overlay: TickMetricsEvent now carries backlogTurns and renderEveryN; the performance overlay displays backlog and current “render every N frames” but no longer mentions catch-up or heartbeats

Learnings during branch development leading to this

Once the worker self-clocks, a separate “catch-up mode” and beats-per-frame knob don’t add real control; they just complicate the model.
Backlog is still a valuable signal, but it’s more effective as a quantitative input (backlog size and whether it’s growing) than as a boolean mode toggle.
Frame skipping should be driven by actual backlog pressure plus frame cost: throttle only while backlog is growing and frames are heavy, and automatically relax back to full-rate rendering once the simulation catches up.
2025-12-11 17:17:48 +01:00
scamiv 7e6717c1b8 Worker now self-clocks; no heartbeats needed
GameRunner exposes pending work via a new hasPendingTurns() so the worker can check whether more ticks need to be processed.
Worker auto-runs ticks: as soon as it initializes or receives a new turn, it calls processPendingTurns() and loops executeNextTick() while hasPendingTurns() is true. No more "heartbeat" message type; the worker no longer depends on the main thread’s RAF loop to advance the simulation.
Client main thread simplified:
Removed CATCH_UP_HEARTBEATS_PER_FRAME, the heartbeat loop, and the lastBeatsPerFrame tracking.
keepWorkerAlive now just manages frame skipping + draining. When it decides to render (based on renderEveryN), it drains pendingUpdates, merges them, updates GameView, and runs renderer.tick().
Because rendering a batch always implies draining, we restored the invariant that every GameView.update is paired with a layer tick() (no more lost incremental updates).
MAX_RENDER_EVERY_N is now 5 to keep the queue from growing too large while the worker sprints.
2025-12-11 17:17:47 +01:00
scamiv e3a6e0bfcc frameskip 2025-12-11 17:17:47 +01:00
scamiv 5e264a54bc Add client catch-up mode
Increase worker heartbeats per frame when far behind server to fast-forward simulation.
Track backlog and expose catch-up status via TickMetricsEvent.
Extend performance overlay to display backlog turns and indicate active catch-up mode.
2025-12-11 17:17:45 +01:00
Roan 8dde30ebb6 Update game timer UI (#2577)
## Description:

- use hh:mm:ss for timer format or mm:ss if no hours are present
- refactor classes and code to be simpler
- move timer inline with the buttons so the whole ui is smaller for more
game space
- update fast forward icon to better represent what it does
- move replay controls below game time ui

### Before:

<img width="218" height="155" alt="image"
src="https://github.com/user-attachments/assets/bfdbe571-3ec5-4c02-840b-112e8e3caab1"
/>
<img width="360" height="171" alt="image"
src="https://github.com/user-attachments/assets/ceee2923-fec8-4ebc-b9de-4b30a47b38a8"
/>
<img width="192" height="136" alt="image"
src="https://github.com/user-attachments/assets/8f8f464c-48e4-42c1-b378-51be2b1fc405"
/>


### After:

<img width="287" height="106" alt="image"
src="https://github.com/user-attachments/assets/30246189-9795-4822-b857-0af524cacb92"
/>
<img width="294" height="180" alt="image"
src="https://github.com/user-attachments/assets/065285ca-ae46-4481-9dd5-00d3bb4fcfb3"
/>
<img width="290" height="182" alt="image"
src="https://github.com/user-attachments/assets/c1b3da39-0785-4d50-8105-c028fa496963"
/>
<img width="213" height="88" alt="image"
src="https://github.com/user-attachments/assets/41e0a84c-2f68-4d24-9923-dd92bb70d161"
/>


## 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:

`rovi.`
2025-12-10 14:51:14 -08:00
Aotumuri 089d9ab402 Fix: update renderSprites based on user settings in SpriteFactory (#2574)
Resolves #2573
 
## Description:
Fixed an issue where structure icons became smaller after upgrading a
building.
In StructureDrawingUtils.ts, renderSprites was always set to true and
never updated, which caused the code to consistently select the
scaled-down icon. This appears to have been the root cause of the
problem. Since StructureIconsLayer (the caller of StructureDrawingUtils)
updates renderSprites based on settings, I aligned the behavior
accordingly.

```ts
    if (type === "icon") {
      const s =
        scale >= ZOOM_THRESHOLD && !this.renderSprites
          ? Math.max(1, scale / ICON_SCALE_FACTOR_ZOOMED_IN)
          : Math.min(1, scale / ICON_SCALE_FACTOR_ZOOMED_OUT);
      parentContainer.scale.set(s);
    }
```

Here is the video demonstrating the behavior after the fix.
Please see the linked issue for the pre-fix behavior.


https://github.com/user-attachments/assets/24c11a39-667e-49eb-adfe-f0c400d91e54

## 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
2025-12-09 19:43:48 -08:00
Roan e104614a85 Consistent border radius and padding from edge of screen for in game UI (#2576)
## Description:

Moves all the in game ui to have a fixed padding around the edge of the
screen and also makes all the in game ui have the same border radius.


Before:

<img width="569" height="802" alt="image"
src="https://github.com/user-attachments/assets/2d51b66c-26bb-4835-abef-a646565280ba"
/>

<img width="2559" height="1238" alt="image"
src="https://github.com/user-attachments/assets/00723649-bfc7-4e92-bee9-6cff0c2d688c"
/>


After: 

<img width="2559" height="1240" alt="image"
src="https://github.com/user-attachments/assets/8dda98e3-8836-4363-8f33-5b699303ee4f"
/>

<img width="686" height="1122" alt="image"
src="https://github.com/user-attachments/assets/a3820d1c-0579-4b2b-b2a8-7eb790e3ec39"
/>




## 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:

`rovi.`
2025-12-09 19:37:52 -08:00
bibizu 0861bbfad5 Enhance: missile silo shows SAM previews (#2578)
## Description:

Missile silos should also show SAM previews for placement consideration.

## 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
2025-12-09 16:26:12 -08:00
Ahmet Dedeler 327d425fd5 Fix obvious typos (#2585)
## Summary
- fix obvious spelling typos flagged by codespell across docs, tests,
comments
- no functional changes

## Testing
- pre-commit hooks (eslint/prettier) ran during commit
2025-12-09 16:12:00 -08:00
evanpelle 1d7685a5bf Merge branch 'v27' 2025-12-09 15:39:49 -08:00
Wraith 7658c67662 optimize(RailroadLayer): throttle color scans, cull blits, and remove (#2565)
## Description:

Render optimizations were applied for RailroadLayer: limiting color
updates, skipping off-screen work, drawing only the visible region, and
preventing O(n) ray tile removals.

## 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
2025-12-07 19:35:07 +00:00
bibizu 97e6c1cd77 feat: Nuke Trajectory SAM intercept prediction (#2541)
## Description:

Overhaul to nuke previews:
- Nuke previews now show when they become invulnerable (if
invulnerability setting enabled).
- Nuke previews now show if a SAM defense could intercept it, and where
the intercept occurs.
- SAMs range is now color-coded and outlined to be able to know if
missile will be intercepted by it.

<img width="1326" height="862" alt="image"
src="https://github.com/user-attachments/assets/4cc43a0b-ebac-4707-85bb-4d422f23da28"
/>

Colors/outlines aren't meant to be final, and there are constants to
play around with at the start of both files.

I also kept the naive implementation since the performance cost isn't
too high from my testing and any improvements I can think of are small
and require a bigger rewrite.

## 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
2025-12-06 11:21:44 -08:00
evanpelle cb4cf091ff update ads 2025-12-05 08:47:48 -08:00
VariableVince 6ca81211ea Alert frame: add to in-game settings, orange for attack instead of red (#2561)
## Description:

The red alert frame for betrayals was added in
https://github.com/openfrontio/OpenFrontIO/pull/1195. It also flashes
red for incoming land attacks since
https://github.com/openfrontio/OpenFrontIO/pull/2358.

The same color for betrayals and attacks leads to confusion. And
possibly red alert fatigue. But when players find themselves fatigued
and want to shut it off for awhile, they can't because the setting
doesn't exist in-game. Also, the setting description on the homepage
settings didn't yet reflect that the alert frame flashes for attacks
too.

This PR fixes this by:

- making the color for land attacks orange. This is well discernable
from red for various colorblindness types, while still looking alarming.
- adding the setting to in-game SettingsModal 
- adding land attack to setting description

Reference to comments on it on Dev Discord:

https://discord.com/channels/1359946986937258015/1381347989464809664/1441232666065240064


https://discord.com/channels/1359946986937258015/1360078040222142564/1434574256704061523

Orange alert frame on being attacked over land:

https://github.com/user-attachments/assets/e0772d62-5b25-4213-a393-dd5af13e8bc9

Settings description change and addition to in-game toggles:
<img width="560" height="160" alt="Added to description what was added
in PR 2358"
src="https://github.com/user-attachments/assets/bc6e2206-b7ac-498d-9009-d2b6e302d3cf"
/>

<img width="665" height="425" alt="In SettingsModal and with attacks
added to description"
src="https://github.com/user-attachments/assets/d489830c-e359-4a5f-8eb4-3caa7d0c21b2"
/>

## 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
2025-12-04 13:26:55 -08:00
VariableVince ec0bf079ef Fix spacing in player team label display (#2560)
## Description:

Add a space after "Your team:"

Before:
<img width="237" height="117" alt="image"
src="https://github.com/user-attachments/assets/60c0821f-a188-44bc-bcd5-e810a741b297"
/>

After:
<img width="243" height="122" alt="image"
src="https://github.com/user-attachments/assets/99b3ff5a-167d-4bae-b8f6-b1b199d4946a"
/>

## 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
2025-12-03 16:37:17 -08:00
Roan 5d513dfe5d Remove border around in game time (#2544)
## Description:

Removes the border around the in game time because it looks better this
way. Sorry my screenshots are a bit washed out, windows doesn't like my
HDR monitor...

Before:
<img width="201" height="145" alt="image"
src="https://github.com/user-attachments/assets/ef399dcd-72bc-4ee7-ac67-42a0e4b2b793"
/>

After:
<img width="213" height="143" alt="image"
src="https://github.com/user-attachments/assets/bdb211af-d2c6-4b5e-8946-1cb88bf707c2"
/>


## 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:

rovi.
2025-11-30 19:00:36 -08:00
FloPinguin 38145254af Alliance icon does no longer stretch/disappear 🖌️ (#2527)
Resolves #2521

## Description:

Small CSS fix so the new alliance icon does not stretch when there are
multiple icons.

## 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
2025-11-26 19:51:21 -08:00
FloPinguin ab53ee687f Alliance icon does no longer stretch/disappear 🖌️ (#2527)
Resolves #2521

## Description:

Small CSS fix so the new alliance icon does not stretch when there are
multiple icons.

## 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
2025-11-26 19:50:58 -08:00
CrackeRR11 8f53785a80 BUG FIX: Gold double deduction + Rmoval of UnitType.Construction (#2378)
## Description:

- Removed the temporary UnitType.Construction and embedded construction
state into real units via isUnderConstruction().
- Centralized non-structure spawning to perform a single validation
right before unit creation/launch.
- Updated UI layers to render construction state without relying on the
removed enum.
- Adjusted and created tests to match the new flow and to cover the
no-refundscenarios.

# Tests updated 
- tests/economy/ConstructionGold.test.ts: covers structure cost
deduction and income, tolerant of passive income; ensures no refunds
during construction.
- tests/nukes/HydrogenAndMirv.test.ts: accounts for single-check launch
flow; MIRV test targets a player-owned tile; ensures launch after
payment.
- tests/client/graphics/UILayer.test.ts: mocks now provide
isUnderConstruction and real type strings;

## 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:

CrackeRR1

---------

Co-authored-by: Evan <evanpelle@gmail.com>
2025-11-26 14:45:14 -08:00
NOBODY 049485cd39 Fix: Correct percentage (%) placement in Persian UI (RTL handling) (#2501)
## Description:

Fixes incorrect RTL rendering where the percentage symbol (%) appeared
before the label in Persian (fa-IR).
The UI now correctly displays values as `20%`.

**Changes:**
- Updated `controlpanel.ts` to fix percentage position.
- 16 additions, 7 deletions.

**Testing:**
1. Switch UI language to Persian (fa-IR).
2. Open control panel with percentage display.
3. Confirm `%` appears after numeric value.
4. Verified no changes in LTR languages.

## 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:

nobodyiran
2025-11-24 10:29:08 -08:00
Rj Manhas a5cdd23c00 feat: added retaliate button (#2426)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #495 

## Description:

Adds a button to quickly retaliate against a incoming attack

<img width="464" height="212" alt="image"
src="https://github.com/user-attachments/assets/4764d261-a408-4d61-a2d2-2685018aa698"
/>


## 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:

notifxy (1379678982676676639)
2025-11-24 09:34:04 -08:00
evanpelle 5fbdea3c39 Show enzo tutorial video on death screen if played less than 3 games 2025-11-22 12:23:33 -08:00
evanpelle 9287d0323d bugfix: emoji table was too small on firefox 2025-11-20 16:49:45 -08:00
Hauke12345 dcf5d1b103 Fading handshake (#2474)
## Description:
Add dynamic alliance icon with time-based fill and extension request
indicator

- Implement bottom-up green fill on alliance icon proportional to
remaining time
- Use AllianceIconFaded.svg as base layer with green overlay clipped
from top
- Add 20-82.40% clip range to account for icon vertical offset 

## 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


<img width="1132" height="631" alt="Screenshot 2025-11-18 205205"
src="https://github.com/user-attachments/assets/4af71ddc-f847-4460-9046-167275efc773"
/>
<img width="1387" height="792" alt="Screenshot 2025-11-18 205532"
src="https://github.com/user-attachments/assets/9dd0e018-323f-4de1-bae8-2633c09fe867"
/>

## Please put your Discord username so you can be contacted if a bug or
regression is found:
hauke4707

---------

Co-authored-by: Evan <evanpelle@gmail.com>
2025-11-19 12:32:01 -08:00
FloPinguin 90b73451a8 Added NameLayer-Icons to PlayerInfoOverlay (#2446)
Resolves #1686

## Description:

Above or behind the player names on the map, there are icons (images
and/or emojis).
This PR also adds these icons to the PlayerInfoOverlay (on the right
side of the player name).
To share the logic, a new file PlayerIcons.ts has been created.

<img width="215" height="355" alt="Screenshot 2025-11-14 024435"
src="https://github.com/user-attachments/assets/2e581ef9-0330-4c9d-9c52-5f943a58e64b"
/>
<img width="203" height="337" alt="Screenshot 2025-11-14 024731"
src="https://github.com/user-attachments/assets/0c2bf278-b8ca-43c2-b466-ea7a83577b25"
/>
<img width="193" height="288" alt="Screenshot 2025-11-14 024639"
src="https://github.com/user-attachments/assets/be114bc6-f3a8-4b8d-b267-025587c9eafe"
/>

The alliance icon is NOT shown because it's already on the left side of
the alliance timer.

### Why is this change needed?

Sometimes you can't quickly find the nametag of a player on the map.
Especially if a player's territory is scattered around the map, maybe
even on several small islands.
But you still want to know if the player is AFK, has a traitor debuff,
etc.
So it's very useful to get this information by just hovering over a
player instead of needing to search for the floating nametag.

## 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: Evan <evanpelle@gmail.com>
2025-11-18 15:03:52 -08:00
Mike Harris 2b44b68362 Feature - Improve Structure Color Contrast (#2454)
If this PR fixes an issue, link it below. If not, delete these two
lines.
Resolves #2447

## Description:

This PR updates the logic used to generate structure fill and border
colors. Currently, (v0.26.16 and earlier), some light territory colors
have structures that are difficult to see and identify. This PR ensures
that all territory colors have structures that are easily visible.

Instead of using `Colord.lighten()` and `Colord.darken()` to generate
structure colors, the logic now:
- queries the territory color and border color of the structure owner
- Converts these colors to the [LAB color
space](https://en.wikipedia.org/wiki/CIELAB_color_space) (which is a
human-perception-uniform color space).
- Darkens the border color (by decreasing LAB luminance) and sometimes
lightens the territory color (by increasing LAB luminance) until a
specific `Color Delta` is achieved (currently `delta > 0.5`)
- This ensures contrast between the structure and the territory
background.

Additionally, this PR re-organizes colors in the `Colors.ts` file for
better visibility and removes redundant colors from the `nationColors`
list.

This PR is an implementation of the proposed mock-up posted on imgur in
issue #2447. Screenshots of the original, final, and side-by-side
comparison of structure colors (for all available player colors) are in
the [imgur
album](https://imgur.com/a/openfront-color-playground-4cxSbbj).

I'd recommend inclusion as a feature/fix for v27.

## 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:

GlacialDrift
2025-11-16 20:58:34 -08:00
scamiv 7373a28c99 Feature/frame profiler (#2467)
## Description:

Adds a reusable FrameProfiler utility, and a way to export profiling
data for offline analysis.


### What this PR changes in the existing performance monitor

This PR enhances the performance monitor by:

- **Introducing a reusable `FrameProfiler` utility**
- New `FrameProfiler` singleton in
`src/client/graphics/FrameProfiler.ts`.
- Profiling is only active when the performance overlay is visible
(toggled via user settings), to avoid unnecessary overhead.

- **Per-layer and span-level timing integration**
  - `GameRenderer.renderGame` now:
    - Clears the profiler at the start of each frame.
- Wraps each `layer.renderLayer?.(this.context)` call with
`FrameProfiler.start()/end()`, keyed by the layer’s constructor name.
- Consumes the recorded timings at the end of the frame and passes them
into `PerformanceOverlay.updateFrameMetrics(frameDuration,
layerDurations)`.
  - `TerritoryLayer` instruments key operations:
    - `renderTerritory`
    - `putImageData`
    - Drawing the main canvas
    - Drawing the highlight canvas during spawn
- These show up in the performance overlay as additional entries (e.g.
`TerritoryLayer:renderTerritory`).

- **JSON export of performance snapshots**
- `PerformanceOverlay` can now build a full performance snapshot
(`buildPerformanceSnapshot`) containing:
    - FPS and frame time stats (current, 60s average, 60s history).
    - Tick metrics (avg/max execution and delay, plus raw samples).
- Layer breakdown (EMA-smoothed avg, max, total time per layer/span).
  - A new “Copy JSON” button:
- Uses `navigator.clipboard.writeText` when available and falls back to
a hidden `<textarea>` + `document.execCommand("copy")`.
- Provides user feedback via a transient status ("Copy JSON" → "Copied!"
or "Failed to copy").

- **Enable/disable functionality hooked into the UI**
  - `FrameProfiler.setEnabled(visible)` is invoked:
    - When the overlay visibility is toggled (`init` → `setVisible`).
- When the overlay re-checks visibility in `updateFrameMetrics`, so the
profiler state stays in sync with user settings.
- When disabled, `FrameProfiler` becomes a no-op (returns `0` from
`start`, ignores `record`/`end`, and `consume` returns an empty object),
ensuring minimal overhead when performance monitoring is off.

- **Performance overlay UX and i18n improvements**
  - New controls:
    - **Reset** button to clear all FPS/tick/layer stats.
    - **Copy JSON** button with a tooltip and transient status text.
  - Visual enhancements:
- Wider overlay (`min-width: 420px`) and extra padding for readability.
    - Layer breakdown section with:
      - A list that is now sorted by total accumulated time.
      - A horizontal bar per entry, scaled by average cost.
      - Avg / max time display per layer/span.
- All new text is routed through `translateText` and backed by
`en.json`:
    - `performance_overlay.reset`
    - `performance_overlay.copy_json_title`
    - `performance_overlay.copy_clipboard`
    - `performance_overlay.copied`
    - `performance_overlay.failed_copy`
    - `performance_overlay.fps`
    - `performance_overlay.avg_60s`
    - `performance_overlay.frame`
    - `performance_overlay.tick_exec`
    - `performance_overlay.tick_delay`
    - `performance_overlay.layers_header`

---

### How to set up profiling for new functions / code paths

For any function or code block you want to profile during a frame:

```ts
import { FrameProfiler } from "../FrameProfiler"; 

function heavyOperation() {
  const spanStart = FrameProfiler.start();
  // ... your existing work ...
  FrameProfiler.end("MyFeature:heavyOperation", spanStart);
}
```

Guidelines:

- Use descriptive, stable names:
  - Prefix with the component or layer name, e.g.:
    - `"TerritoryLayer:prepareTiles"`
    - `"GameRenderer:resolveVisibility"`
    - `"FooFeature:fetchData"`
- The same name can be called multiple times per frame; the profiler
accumulates the durations in that frame.
- The accumulated values will appear:
  - In `layerDurations` consumed at the end of the frame.
  - In the overlay “Layers (avg / max, sorted by total time)” section.
  - In the exported JSON under `layers` with `avg`, `max`, and `total`.

**3. Record pre-computed durations (optional)**

If you already have a measured duration and just want to attach it:

```ts
FrameProfiler.record("MyFeature:step1", someDurationInMs);
```

- This is equivalent to calling `start`/`end` but with your own timing
logic.
- Again, multiple calls with the same name in one frame will be summed.

---

<img width="466" height="823" alt="image"
src="https://github.com/user-attachments/assets/354b249a-25eb-4c3f-bd2e-9906372f761b"
/>


## 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

- [ ] 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

---------

Co-authored-by: Evan <evanpelle@gmail.com>
2025-11-16 19:10:20 -08:00
Rj Manhas a24710a9f5 A timer and icon flashing for betryal debuff (#2430)
Resolves #2096 

## Description:

(TO CLEARIFY THEIRS NO GRACE PERIOD ADDED, AS THAT ISSUE THAT WOULD OF
NEEDED IT WAS FIXED BEFORE ON ITS OWN)

Shows the amount left in the UI for the player who trigged it
<img width="374" height="80" alt="image"
src="https://github.com/user-attachments/assets/f269c015-5a78-4e85-a9c0-cdf039d93d2a"
/>

also the betryal icon, after 15 seconds starts a slow flash, then after
10 seconds it speeds up, and then at 5 seconds it quickly flashs.

this was a nice way to show the time left without adding any new ui
componets.


video link 36 seconds (https://streamable.com/cwzxch)

## 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:

notifxy (1379678982676676639)
2025-11-11 13:39:01 -08:00
Bilgehan Demirkaya 508849a8af Fix Emoji Panel Z-Index (#2421)
## Description: Fix Emoji Panel Hidden Behind Player Info Panel

According to : https://github.com/openfrontio/OpenFrontIO/issues/2367

After my previous Player Info Panel layout fix, the Emoji Panel was
accidentally rendered behind it (see
[comment](https://github.com/openfrontio/OpenFrontIO/pull/2410#issuecomment-3507266463)).

This PR updates EmojiTable.ts to ensure the Emoji Panel displays
correctly in front of the Player Info Panel.

Changes:

Increased z-index values for the Emoji backdrop, content, and close
button above z-[10001].

backdrop: z-[10002]

content: z-[10003]

close button: z-[10004]

Expected outcome:
The Emoji picker (backdrop, content, and close button) now correctly
appears above the Player Panel.

<img width="1325" height="857" alt="Ekran Resmi 2025-11-09 09 42 38"
src="https://github.com/user-attachments/assets/08f81d88-70be-4690-b13f-01f09766df04"
/>

- [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

Discord Username : bilgehandk
2025-11-10 16:34:03 -08:00
VariableVince d07f84f801 Move warship by a touch (of magic) (#2408)
## Description:

This adds moving warships by tapping them on a touchscreen. Now you can
steer them just like you already could with a mouse.

Also has some earlier returns, doing checks only when needed, prevent as
much duplicate checks and a bugfix.

In onMouseUp:
- early return if no OceanTile. Before, function findWarshipsNearCell
would still go look for warships even if ocean wasn't clicked.
- Move const nearbyWarShips down. It isn't needed when this.selectedUnit
is true.
- Remove unnecessary const clickedWarship.
- Move getting clickRef from function findWarshipsNearCell into
onMouseUp. Because it is needed in case of this.selectedUnit too, within
onMouseUp.
Getting a valid clickRef for this.selectedUnit fixes: Runtime error when
clicking outside the map after selecting a warship. The isValidCoord/Ref
check was missing for this.selectedUnit.

For findWarshipsNearCell:
- moved the cell/tile checks out to onMouseUp, the only caller of the
function.
- did NOT rename findWarshipsNearCell. Although it now uses tileRef as
input. Renaming can cause merge issues so i only do this when needed.

Added onTouch:
- Tests if we need to look for warships to select/move or if we can open
Radial Menu.
- Prevent as much duplicated checks as possible. So if no there's no
Ocean Tile found, just send the radial menu event, which checks
isValidCoord anyway. isOceanTile itself works fine even if it's no valid
cell (proven by this.selectedUnit working all this time in onMouseUp
without an isValidCoord test).

Screencap on mobile, shows selecting and moving warships, no runtime
error when clicking outside the map after selecting a warship, while
radial menu still opens as normal:


https://github.com/user-attachments/assets/1300d557-ae2f-46e3-92bd-d434c523aae7

## 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
2025-11-07 20:09:03 -08:00
evanpelle d16a2485e3 Merge branch 'v26' 2025-11-07 19:54:27 -08:00
Bilgehan Demirkaya b44dca16e9 Fix Player Panel, Player Info Overlay and Emoji Table responsive and scrollable on small viewports (#2410)
## Description: Fixes a usability issue where the Player Info Panel and
Emoji Table overflowed the viewport on smaller screens, hiding key
controls (like Stop Trade) behind the Build Bar/Menu. Makes these panels
responsive and scrollable with minimal, low-risk CSS changes.
According to : https://github.com/openfrontio/OpenFrontIO/issues/2367

<img width="1120" height="774" alt="Ekran Resmi 2025-11-07 23 06 01"
src="https://github.com/user-attachments/assets/6fe23c23-ab5b-4254-8872-9880c322e164"
/>

Changes:
- Increased overlay z-index from 1001 to 10001 to ensure it renders
above Build Menu.
- Replaced static layout with scrollable inner container:
- Applied `max-height: calc(100vh - 120px -
env(safe-area-inset-bottom))`
- Enabled scrolling with `overflow: auto` and
`-webkit-overflow-scrolling: touch`
- Added sticky header with close (✕) button for persistent visibility
during scroll.
- Removed unused `init()` method for cleanup.

Discord: bilgehandk
2025-11-07 16:00:14 -08:00
James R 75ca7b1b1e feat: improve emoji panel UI and UX (#2383)
Added some basic fixes:

- Add backdrop overlay with outside-click-to-close 
- Reduce emoji button sizes to fit all emojis without scrolling
- Update styling to match player info panel theme

## Description:
I updated the emoji panel such as reducing the size so it fits on the
screen without scrolling for emojis, and ability to close the panel by
clicking outside of it. Previously you couldn't close the panel by
clicking outside of it, and this was inconsistent with the rest of the
UI. I also updated the styling to match the panel before that (the
player info panel).

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [ ] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [ ] 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:

insane.p

<img width="1237" height="874" alt="image"
src="https://github.com/user-attachments/assets/5c0bd229-0f9b-489d-bc34-a4a70021b78d"
/>

---------

Co-authored-by: Evan <evanpelle@gmail.com>
2025-11-06 15:51:01 -08:00
Mykola 25ea11114e Random spawn (#2375)
## Description:

https://github.com/openfrontio/OpenFrontIO/issues/2352

This is my first PR in this project, and I’ll continue refining it based
on feedback.

<img width="1088" height="859" alt="image"
src="https://github.com/user-attachments/assets/07f4f8b1-52fa-4136-add4-19b00aefd963"
/>

<img width="1157" height="783" alt="image"
src="https://github.com/user-attachments/assets/1c5be80d-72f8-4ead-8d4b-706a3a04fd73"
/>

<img width="1488" height="777" alt="image"
src="https://github.com/user-attachments/assets/4d743548-f0c3-4579-963b-43676f68fab1"
/>

<img width="1499" height="778" alt="image"
src="https://github.com/user-attachments/assets/f808e44f-ef97-467f-9e41-812e2857c36e"
/>


## 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:

nikolaj_mykola

---------

Co-authored-by: Evan <evanpelle@gmail.com>
2025-11-06 15:49:37 -08:00
Kerod Kibatu 020486686f Add Visual Alert when Attacked (#2358)
## Description:

Added prominent red alert notifications for incoming land attacks,
reusing the existing betrayal alert mechanism. Players will now receive
visual feedback when they are being attacked, improving awareness of
incoming threats.

Addressing #2355

## Please complete the following:

- [x] I have added screenshots for all UI updates
> <img width="2559" height="1436" alt="image"
src="https://github.com/user-attachments/assets/cd69a58d-764f-4910-8006-a143685a771a"
/>

- [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:

kerverse
2025-11-06 15:47:04 -08:00
evanpelle a0c4a2a6cc increase header ad to 2 minutes in game 2025-11-05 15:42:32 -08:00
Philipp Allweyer 5dde4cc16d Extend SAM Range to cover Hydros when stacked (#2351)
## Description:

Implements SAM range extension for stacked SAMs to cover hydros as
requested in #2347 and many times from users in discord.
This implementation is as simple as possible: At level 5 and higher,
SAMs extend their range to the range of a hydrogen bomb + 10 for a small
safety margin. Levels 2-4 are interpolated between.

Screenshot to show the sizes compared to a hydro:
<img width="400" alt="image"
src="https://github.com/user-attachments/assets/a857d66c-e3d4-467f-855f-3539cc90b719"
/>

Everything works together with the new range UI, although I might need
to unify with / rebase on #2350. Not yet tested with #2348, but
shouldn't be an issue.

## Input needed:
- Should I add tests for this?
- This is in effect a massive buff to SAMs, might be too strong. Popular
ideas / suggestions from Discord to balance things:
  - Cap the SAM upgrade level at the maximum range (easy to do)
- Alternative, instead of capping the level, decrease the range when
missiles are reloading
- Increase the cost scaling for SAMs per stack, and scale way higher
(e.g. 1.5M > 3M > 4.5M > 6M or something like that) (UI integration
unclear, breaks with existing cost logic)
  - Decrease SAM hit probability for Hydros

I'm happy to implement any of these paths, or just roll with the simple
way it's set up now, just let me know.

## 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:

newyearnewphil

---------

Co-authored-by: Evan <evanpelle@gmail.com>
2025-11-05 11:15:00 -08:00
VariableVince 6fe81cbcb6 Team leaderboard: own team bold + fix headers allignment (#2336)
## Description:

Closes #2185. Made own team name bold in Team Stats. In Show Unit and
Show Control. This follows
https://github.com/openfrontio/OpenFrontIO/pull/2221 which made team
mate names bold in the Leaderboard.

Also fixed column names allignment. They sat in different vertical
positions before.

**BEFORE**

<img width="836" height="402" alt="image"
src="https://github.com/user-attachments/assets/fe2c84b1-c1e4-4415-8df8-ffce657b1b90"
/>

<img width="1050" height="405" alt="image"
src="https://github.com/user-attachments/assets/3a277722-731d-4410-90e6-1fd01c628a5f"
/>


**AFTER**

<img width="840" height="393" alt="image"
src="https://github.com/user-attachments/assets/26db2e81-e39c-451d-9da3-c24061cf6687"
/>

<img width="1061" height="398" alt="image"
src="https://github.com/user-attachments/assets/3dd25369-b355-42f4-bdac-2e6d6d684689"
/>


## 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

---------

Co-authored-by: Evan <evanpelle@gmail.com>
2025-11-05 10:25:12 -08:00
Kerod Kibatu 7b85114194 Add nuke trail preview (#2350)
## Description:

Implements trajectory preview for nuke selection as requested in #2346.
When selecting an AtomBomb or HydrogenBomb, a dashed line preview now
shows the trajectory path from the launch silo to the target location
before launching. Line uses player's territory color with 70% opacity
and dashed pattern for clear visibility

## Please complete the following:

- [x] I have added screenshots for all UI updates
<img width="716" height="483" alt="image"
src="https://github.com/user-attachments/assets/4c263230-34ba-4e56-9502-4a59c84b5943"
/>
<img width="1199" height="965" alt="image"
src="https://github.com/user-attachments/assets/72eda758-e192-45a0-b01d-5a8f413a07d5"
/>

- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file (No new text strings added)
- [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:

kerverse

---------

Co-authored-by: Evan <evanpelle@gmail.com>
2025-11-05 10:25:01 -08:00
evanpelle e8a04d9a72 Merge branch 'v26' 2025-11-04 16:08:15 -08:00
Kerod Kibatu 822d08bb7c Add performance stats (#2338)
## Description:

Enhanced the performance overlay to display additional tick-related
performance metrics. The overlay now shows:

1. **Tick Execution Duration** - Average and maximum time (in
milliseconds) it takes to execute a game tick
2. **Tick Delay** - Average and maximum time (in milliseconds) between
receiving tick updates from the server

The server sends 10 updates per second (100ms interval), so these
metrics help identify:
- Client-side performance bottlenecks (tick execution duration)
- Network latency issues (tick delay)

**Additional improvements:**
- Renamed `FPSDisplay` component to `PerformanceOverlay` to better
reflect its expanded purpose
- Updated method names (`updateFPS` → `updateFrameMetrics`) and CSS
classes for consistency

All metrics are tracked over the last 60 ticks, providing rolling
averages and maximum values for performance analysis.

## Please complete the following:

- [x] I have added screenshots for all UI updates:
- <img width="495" height="227" alt="image"
src="https://github.com/user-attachments/assets/142b0313-61bf-46cc-b595-61fe73f6b54c"
/>


- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- Translation keys already exist in en.json for
"performance_overlay_label" and "performance_overlay_desc"

- [x] I have added relevant tests to the test directory
  - All existing tests pass (309/310 tests passed)
  - No new tests added as this is primarily a display enhancement

- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
  - Tested locally with npm test
  - Verified performance overlay displays all metrics correctly
  - Confirmed tick metrics are calculated and displayed accurately

## Please put your Discord username so you can be contacted if a bug or
regression is found:

Discord: kerverse

---------

Co-authored-by: Evan <evanpelle@gmail.com>
2025-11-04 15:56:44 -08:00
Thomas Cruveilher 45539623fc fix(replay): change text to 'replay speed' when watching a replay #2357 (#2365)
Before, the condition was "if it's not singleplayer", but replays are
counted as singleplayer game for some reason (will need to fix the
underlying issue) so it wasn't robust enough Now the condition is based
on are we in replay or not,.

## Description:

Related to issue https://github.com/openfrontio/OpenFrontIO/issues/2357

I cannot get to replay games locally for some reason (client just throws
an error that it cannot load the lobby), so I made sure that the
singleplayer text did not change (at least no regression) cf screenshot:

<img width="1920" height="963" alt="Screenshot 2025-11-02 at 17 46 57"
src="https://github.com/user-attachments/assets/27e055a8-3813-46bd-a8ae-0c463a94d1a8"
/>


## 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:

sorikairo
2025-11-04 15:56:33 -08:00
iamlewis c0c31a980b Discord and OFM advert added (#2380)
## Description:

Adds a win modal for OFM and the main discord. Adds needed translation
keys and an OFM picture back to the resources file

## 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:

Iamlewis

---------

Co-authored-by: evanpelle <evanpelle@gmail.com>
2025-11-04 15:56:27 -08:00
iamlewis bd4bbdeeb1 Discord and OFM advert added (#2380)
## Description:

Adds a win modal for OFM and the main discord. Adds needed translation
keys and an OFM picture back to the resources file

## 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:

Iamlewis

---------

Co-authored-by: evanpelle <evanpelle@gmail.com>
2025-11-04 15:56:02 -08:00
evanpelle 4144628808 Revert "Halloween Event (#2285)"
This reverts commit b69adf70b3.
2025-11-04 09:26:48 -08:00