Skip to content

Conversation

@icslucas
Copy link
Contributor

@icslucas icslucas commented Oct 26, 2025

Description:

Add main menu music+moving bg
Describe the PR.
Add main menu music+moving bg

Please complete the following:

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

Lucas

@icslucas icslucas requested a review from a team as a code owner October 26, 2025 12:25
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 26, 2025

Walkthrough

Adds main-menu music playback and volume controls: new locale keys, UserSettings getter/setter for main-menu volume, a MenuSoundManager singleton to play/stop/cycle menu tracks, client integration to start/stop and apply volume, plus a subtle background animation change.

Changes

Cohort / File(s) Summary
Language Keys
resources/lang/en.json
Added main_menu_music_volume and main_menu_music_volume_desc; renamed background_music_volume label to "In-Game Music Volume".
Core Settings
src/core/game/UserSettings.ts
Added mainMenuMusicVolume(): number (default 0.2) and setMainMenuMusicVolume(volume: number): void.
Menu Sound Manager
src/client/sound/MenuSoundManager.ts
New default-exported singleton managing multiple Howl tracks, cycling playback, and exposing playBackgroundMusic(), stopBackgroundMusic(), setBackgroundMusicVolume(volume: number).
Sound Playlist Update
src/client/sound/SoundManager.ts
Imported two additional tracks and added two Howl entries, expanding the background playlist.
Client Integration
src/client/Main.ts, src/client/UserSettingModal.ts
Main.ts applies settings and starts/stops menu music during lifecycle; UserSettingModal.ts adds a main-menu music slider and onMenuVolumeChange() to persist/apply value via MenuSoundManager.
Visual & Animation
src/client/index.html
.bg-image background-size set to 200%; added move-background 200s linear infinite animation for subtle horizontal movement.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User
    participant AppMain as Main
    participant Settings as UserSettings
    participant MenuSM as MenuSoundManager
    participant Howler

    User->>AppMain: start app
    AppMain->>Settings: mainMenuMusicVolume()
    Settings-->>AppMain: 0.2
    AppMain->>MenuSM: setBackgroundMusicVolume(0.2)
    MenuSM->>Howler: set volume on tracks
    AppMain->>MenuSM: playBackgroundMusic()
    MenuSM->>Howler: play current track
    Howler-->>MenuSM: onend
    MenuSM->>MenuSM: playNext() -> advance index
    MenuSM->>Howler: play next track
Loading
sequenceDiagram
    autonumber
    participant User
    participant Slider
    participant Modal as UserSettingModal
    participant Settings as UserSettings
    participant MenuSM as MenuSoundManager

    User->>Slider: adjust (0–100)
    Slider->>Modal: CustomEvent { value }
    Modal->>Modal: onMenuVolumeChange(value)
    Modal->>Settings: setMainMenuMusicVolume(value/100)
    Modal->>MenuSM: setBackgroundMusicVolume(value/100)
    MenuSM-->>User: audible volume change
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect Howler onend handlers and cyclical play logic in src/client/sound/MenuSoundManager.ts.
  • Verify numeric validation, persistence, and event wiring in src/client/UserSettingModal.ts.
  • Confirm startup/teardown ordering in src/client/Main.ts so music doesn't race with UI transitions.

Possibly related PRs

Suggested labels

Feature - Frontend, UI/UX

Suggested reviewers

  • evanpelle

Poem

🎵 A gentle loop begins to play,
A slider tames the menu's sway,
Tracks rotate in ordered queue,
Small strings changed, the motion new,
The interface hums soft all day.

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: adding music to the main menu and implementing a moving background animation on the main menu.
Description check ✅ Passed The description is related to the changeset, mentioning the core features (main menu music and moving background) and confirming completion of standard checks like translation updates and testing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec7be09 and d8bb2dc.

📒 Files selected for processing (1)
  • resources/lang/en.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • resources/lang/en.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: 🎨 Prettier
  • GitHub Check: Deploy to openfront.dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@icslucas icslucas added this to the v27 milestone Oct 26, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (4)
src/client/Main.ts (1)

514-514: Consider: Should music resume when returning to main menu?

The music stops when joining a lobby, but there's no code to resume it when the player exits back to the main menu. Consider whether music should restart in handleLeaveLobby() (line 578).

If desired, add to handleLeaveLobby:

private async handleLeaveLobby(/* event: CustomEvent */) {
  if (this.gameStop === null) {
    return;
  }
  console.log("leaving lobby, cancelling game");
  this.gameStop();
  this.gameStop = null;
  this.gutterAds.hide();
  this.publicLobby.leaveLobby();
  
  // Resume menu music
  MenuSoundManager.setBackgroundMusicVolume(
    this.userSettings.mainMenuMusicVolume(),
  );
  MenuSoundManager.playBackgroundMusic();
}
src/client/index.html (1)

62-82: Performance consideration: Animating background-position can impact performance.

The background animation continuously moves a 200% scaled image over 200 seconds. On lower-end devices or mobile, animating background-position can cause repaints and affect performance. Consider using CSS transform with will-change for better GPU acceleration.

More performant alternative:

.bg-image {
  background-size: 200%;
  background-position: 0% 50%;
  transform: translateX(0);
  will-change: transform;
  animation: move-background 200s linear infinite;
}

@keyframes move-background {
  0% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(-50%);
  }
  100% {
    transform: translateX(0);
  }
}

However, with transform, you'll need to adjust the implementation since background-position and transform work differently for backgrounds. The current implementation is acceptable if performance is not a concern.

src/client/sound/MenuSoundManager.ts (2)

34-41: Consider: Guard against rapid repeated calls.

If playBackgroundMusic() is called multiple times rapidly, the playing() check might have race conditions. While the guard prevents playing multiple instances, consider adding a lock or state flag for better safety.

Example with explicit state tracking:

private isPlaying: boolean = false;

public playBackgroundMusic(): void {
  if (this.backgroundMusic.length > 0 && !this.isPlaying) {
    this.isPlaying = true;
    this.backgroundMusic[this.currentTrack].play();
  }
}

public stopBackgroundMusic(): void {
  if (this.backgroundMusic.length > 0 && this.isPlaying) {
    this.backgroundMusic[this.currentTrack].stop();
    this.isPlaying = false;
  }
}

private playNext(): void {
  this.isPlaying = false;
  this.currentTrack = (this.currentTrack + 1) % this.backgroundMusic.length;
  this.playBackgroundMusic();
}

62-62: Consider: Singleton instantiation could fail if audio context not ready.

Exporting a singleton instance created immediately could fail if the browser's audio context isn't ready or if the module loads before DOM is ready. The current implementation works because it's only called after DOMContentLoaded in Main.ts, but this coupling is fragile.

Consider lazy initialization:

class MenuSoundManager {
  private static instance: MenuSoundManager | null = null;
  
  private constructor() {
    // ... existing constructor code
  }
  
  public static getInstance(): MenuSoundManager {
    if (!MenuSoundManager.instance) {
      MenuSoundManager.instance = new MenuSoundManager();
    }
    return MenuSoundManager.instance;
  }
  
  // ... rest of the class
}

export default MenuSoundManager.getInstance();

Or keep it simple but document the initialization dependency.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3478b3a and 010688e.

⛔ Files ignored due to path filters (3)
  • proprietary/sounds/music/iron-horizon.mp3 is excluded by !**/*.mp3
  • proprietary/sounds/music/prelude-to-war.mp3 is excluded by !**/*.mp3
  • proprietary/sounds/music/world-divided.mp3 is excluded by !**/*.mp3
📒 Files selected for processing (7)
  • .husky/pre-commit (1 hunks)
  • resources/lang/en.json (1 hunks)
  • src/client/Main.ts (3 hunks)
  • src/client/UserSettingModal.ts (3 hunks)
  • src/client/index.html (1 hunks)
  • src/client/sound/MenuSoundManager.ts (1 hunks)
  • src/core/game/UserSettings.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/client/UserSettingModal.ts (1)
src/client/LangSelector.ts (1)
  • translateText (254-274)
🪛 GitHub Actions: 🧪 CI
src/client/Main.ts

[warning] 1-1: Prettier formatting issue detected. Run 'npx prettier --write' to fix code style issues in this file.

src/client/UserSettingModal.ts

[warning] 1-1: Prettier formatting issue detected. Run 'npx prettier --write' to fix code style issues in this file.

src/client/sound/MenuSoundManager.ts

[warning] 1-1: Prettier formatting issue detected. Run 'npx prettier --write' to fix code style issues in this file.

🔇 Additional comments (5)
src/client/UserSettingModal.ts (2)

210-219: Good implementation of volume change handler.

The handler correctly:

  • Converts slider value (0-100) to volume (0-1)
  • Updates persistent storage via setMainMenuMusicVolume
  • Applies volume immediately via MenuSoundManager.setBackgroundMusicVolume
  • Includes error handling for missing detail.value

288-296: Good: Volume control placed prominently at top of settings.

The main menu music slider is positioned first in basic settings, making it easy for users to find and adjust. The translation keys are properly referenced.

resources/lang/en.json (1)

390-393: Good: Clear distinction between menu and in-game music.

The language keys now clearly separate "Main Menu Music" from "In-Game Music Volume", improving user understanding. The descriptions are clear and concise.

src/client/sound/MenuSoundManager.ts (2)

49-54: Good: Volume clamping and applying to all tracks.

The method correctly clamps volume to [0, 1] range and applies it to all tracks, ensuring consistent behavior.


2-4: Licensing properly documented—no issues to address.

The music files are correctly placed in the /proprietary directory with clear licensing terms. LICENSE-ASSETS explicitly distinguishes the three asset categories: open CC BY-SA 4.0 resources, proprietary restricted assets, and external CDN assets. The imported files (iron-horizon.mp3, world-divided.mp3, prelude-to-war.mp3) are intentionally kept proprietary and restricted to OpenFront development use, which is documented in both /proprietary/LICENSE and LICENSE-ASSETS. This mixed licensing approach (AGPL-3.0 code + CC BY-SA 4.0 open assets + restricted proprietary assets) is valid and transparent.

coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 26, 2025
coderabbitai[bot]

This comment was marked as resolved.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is unrelated to the background music, can you put it in another PR? Looks good though

Comment on lines +288 to +298
<!-- Main Menu Music -->
<setting-slider
label="${translateText("user_setting.main_menu_music_volume")}"
description="${translateText(
"user_setting.main_menu_music_volume_desc",
)}"
min="0"
max="100"
.value=${this.userSettings.mainMenuMusicVolume() * 100}
@change=${this.onMenuVolumeChange}
></setting-slider>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't we already have a music setting?

@github-actions
Copy link

This pull request is stale because it has been open for fourteen days with no activity. If you want to keep this pull request open, add a comment or update the branch.

@github-actions github-actions bot added the Stale PRs that haven't been touched for over two weeks. label Nov 20, 2025
@github-actions github-actions bot removed the Stale PRs that haven't been touched for over two weeks. label Nov 21, 2025
@ryanbarlow97 ryanbarlow97 modified the milestones: v27, v28 Nov 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants