refactor: restructure game menu with two-row tab layout

- Split category tabs into two rows: row 1 (tabletop, cards, casino, word),
  row 2 (logic) for better screen real estate
- Move title text and adjust vertical positioning to accommodate tabs
- Center row 2 tabs independently based on active categories
- Update game grid top position to 370px for proper spacing
- Update game-icons and tab-icons assets for new layout
This commit is contained in:
Brian Fertig 2026-06-08 18:26:42 -06:00
parent 3d3d09a9fb
commit 58f72e3d91
5 changed files with 33 additions and 10 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

View File

@ -32,12 +32,12 @@ export default class GameMenuScene extends Phaser.Scene {
this.add.image(cx, GAME_HEIGHT / 2, 'bg-menu').setDisplaySize(GAME_WIDTH, GAME_HEIGHT);
addFullscreenButton(this);
const titleText = this.add.text(cx, 120, 'Choose a game', {
const titleText = this.add.text(cx, 60, 'Choose a game', {
fontFamily: 'Righteous',
fontSize: '64px',
color: COLORS.textHex,
}).setOrigin(0.5).setDepth(1);
this.add.rectangle(cx, 120, titleText.width + 64, titleText.height + 28, 0x000000, 0.7);
this.add.rectangle(cx, 60, titleText.width + 64, titleText.height + 28, 0x000000, 0.7);
const loadingText = this.add.text(cx, 540, 'Loading game list…', {
fontSize: '24px', color: COLORS.mutedHex,
@ -61,12 +61,20 @@ export default class GameMenuScene extends Phaser.Scene {
this._gameObjects = [];
this._tabs = {};
const activeCats = CATEGORIES.filter(({ key }) => this._gamesByCategory[key].length > 0);
const tabSpacing = Math.min(420, 1800 / activeCats.length);
const tabStartX = cx - (tabSpacing * (activeCats.length - 1)) / 2;
// Two-row tab layout: row 1 has 4 categories, row 2 has the rest
const ROW1_KEYS = ['tabletop', 'cards', 'casino', 'word'];
const ROW2_KEYS = ['logic'];
const ROW1 = CATEGORIES.filter(c => ROW1_KEYS.includes(c.key));
const ROW2 = CATEGORIES.filter(c => ROW2_KEYS.includes(c.key));
const activeRow1 = ROW1.filter(({ key }) => this._gamesByCategory[key].length > 0);
const activeRow2 = ROW2.filter(({ key }) => this._gamesByCategory[key].length > 0);
activeCats.forEach(({ key, label }, i) => {
const btn = new Button(this, tabStartX + i * tabSpacing, 230, label, () => this.showCategory(key), {
const tabSpacing = Math.min(420, 1800 / activeRow1.length);
const tabStartX = cx - (tabSpacing * (activeRow1.length - 1)) / 2;
// Row 1 tabs
activeRow1.forEach(({ key, label }, i) => {
const btn = new Button(this, tabStartX + i * tabSpacing, 170, label, () => this.showCategory(key), {
width: 390,
variant: 'ghost',
});
@ -74,8 +82,23 @@ export default class GameMenuScene extends Phaser.Scene {
this._tabs[key] = btn;
});
// Row 2 tabs (centered)
if (activeRow2.length > 0) {
const row2Spacing = Math.min(420, 1800 / activeRow2.length);
const row2StartX = cx - (row2Spacing * (activeRow2.length - 1)) / 2;
activeRow2.forEach(({ key, label }, i) => {
const btn = new Button(this, row2StartX + i * row2Spacing, 250, label, () => this.showCategory(key), {
width: 390,
variant: 'ghost',
});
btn.text.setX(40);
this._tabs[key] = btn;
});
}
this._tabIcons = {};
activeCats.forEach(({ key }) => {
const allActiveCats = [...activeRow1, ...activeRow2];
allActiveCats.forEach(({ key }) => {
const btn = this._tabs[key];
const icon = this.add.image(btn.x + ICON_X_OFFSET, btn.y, 'tab-icons', TAB_ICON_FRAMES[key])
.setDisplaySize(ICON_INACTIVE, ICON_INACTIVE);
@ -83,7 +106,7 @@ export default class GameMenuScene extends Phaser.Scene {
this._tabIcons[key] = icon;
});
const startKey = activeCats.find(c => c.key === _lastCategory) ? _lastCategory : activeCats[0].key;
const startKey = allActiveCats.find(c => c.key === _lastCategory) ? _lastCategory : allActiveCats[0].key;
this.showCategory(startKey);
new Button(this, cx, GAME_HEIGHT - 100, 'Back', () => this.scene.start('Landing'), { variant: 'ghost' });
@ -152,7 +175,7 @@ export default class GameMenuScene extends Phaser.Scene {
const COLS = 3;
const COL_SPACING = 520;
const ROW_SPACING = 90;
const GRID_TOP = 340;
const GRID_TOP = 370;
const BTN_WIDTH = 360;
const PADDING = 52;
const QBTN_SIZE = 44;