Fix build errors: Phaser SSR, TypeScript types, and ArenaScene logic

- Use next/dynamic with ssr:false for Phaser game page
- Change tsconfig target to ES2022 for BigInt support
- Replace Phaser default imports with namespace imports
- Fix ArenaScene button logic using phase state machine
- Remove invalid add:false from Phaser graphics config
- Fix MatchState commitDeadline type

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ubuntu 2026-05-24 02:29:32 +00:00
parent 52565bf1a3
commit dbe6a90e93
14 changed files with 14672 additions and 52 deletions

8113
apps/contracts/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["./test/**/*", "./ignition/**/*"],
"files": ["./hardhat.config.ts"]
}

6
apps/web/next-env.d.ts vendored Normal file
View file

@ -0,0 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View file

@ -0,0 +1,22 @@
'use client';
import { useEffect, useRef } from 'react';
import { initGame } from '@/phaser/Game';
export default function PlayClient() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!containerRef.current) return;
const game = initGame('phaser-container');
return () => {
game.destroy(true);
};
}, []);
return (
<div className="w-full h-screen flex items-center justify-center bg-slate-950">
<div id="phaser-container" ref={containerRef} className="w-full h-full"></div>
</div>
);
}

View file

@ -1,22 +1,9 @@
'use client';
import { useEffect, useRef } from 'react';
import { initGame } from '@/phaser/Game';
import dynamic from 'next/dynamic';
const PlayClient = dynamic(() => import('./PlayClient'), { ssr: false });
export default function PlayPage() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!containerRef.current) return;
const game = initGame('phaser-container');
return () => {
game.destroy(true);
};
}, []);
return (
<div className="w-full h-screen flex items-center justify-center bg-slate-950">
<div id="phaser-container" ref={containerRef} className="w-full h-full"></div>
</div>
);
return <PlayClient />;
}

View file

@ -1,8 +1,8 @@
import Phaser from 'phaser';
import { BootScene } from './scenes/BootScene.js';
import { LobbyScene } from './scenes/LobbyScene.js';
import { ArenaScene } from './scenes/ArenaScene.js';
import { ResultScene } from './scenes/ResultScene.js';
import * as Phaser from 'phaser';
import { BootScene } from './scenes/BootScene';
import { LobbyScene } from './scenes/LobbyScene';
import { ArenaScene } from './scenes/ArenaScene';
import { ResultScene } from './scenes/ResultScene';
export function initGame(parent: string) {
return new Phaser.Game({

View file

@ -1,4 +1,4 @@
import Phaser from 'phaser';
import * as Phaser from 'phaser';
export class UIButton extends Phaser.GameObjects.Container {
private bg: Phaser.GameObjects.Rectangle;

View file

@ -1,6 +1,6 @@
import Phaser from 'phaser';
import { UIButton } from '../objects/UIButton.js';
import { socket } from '@/lib/socket.js';
import * as Phaser from 'phaser';
import { UIButton } from '../objects/UIButton';
import { socket } from '@/lib/socket';
import { keccak256, solidityPacked } from 'ethers';
import { Choice, MatchStatus } from '@rps-royale/shared';
@ -25,7 +25,8 @@ export class ArenaScene extends Phaser.Scene {
private infoText!: Phaser.GameObjects.Text;
private choiceButtons: UIButton[] = [];
private actionButton!: UIButton;
private particles!: Phaser.GameObjects.Particles;
private particles!: any;
private phase: 'commit' | 'reveal' = 'commit';
constructor() {
super({ key: 'ArenaScene' });
@ -83,7 +84,8 @@ export class ArenaScene extends Phaser.Scene {
// Action button (commit / reveal)
this.actionButton = new UIButton(this, width / 2, height / 2 + 160, 'Valider le Commit', () => {
this.sendCommit();
if (this.phase === 'commit') this.sendCommit();
else if (this.phase === 'reveal') this.sendReveal();
});
this.actionButton.setDisabled(true);
@ -206,18 +208,12 @@ export class ArenaScene extends Phaser.Scene {
}
startRevealPhase() {
this.phase = 'reveal';
this.cameras.main.zoomTo(1, 500, 'Sine.easeOut');
this.statusText.setText('RÉVÈLE TON CHOIX').setColor('#22d3ee');
this.infoText.setText('Dévoile ton signe pour déterminer le gagnant');
this.actionButton.setLabel('Révéler');
this.actionButton.setDisabled(false);
// Change action button to reveal
this.actionButton['bg']?.off('pointerdown');
this.actionButton['bg']?.on('pointerdown', () => {
if (this.actionButton['disabled']) return;
this.sendReveal();
});
}
sendReveal() {
@ -233,7 +229,7 @@ export class ArenaScene extends Phaser.Scene {
}
createParticles() {
const graphics = this.make.graphics({ x: 0, y: 0, add: false });
const graphics = this.make.graphics({ x: 0, y: 0 });
graphics.fillStyle(0xffffff, 1);
graphics.fillCircle(4, 4, 4);
graphics.generateTexture('spark', 8, 8);

View file

@ -1,5 +1,5 @@
import Phaser from 'phaser';
import { UIButton } from '../objects/UIButton.js';
import * as Phaser from 'phaser';
import { UIButton } from '../objects/UIButton';
export class BootScene extends Phaser.Scene {
constructor() {
@ -46,7 +46,7 @@ export class BootScene extends Phaser.Scene {
});
// Create a simple flare texture procedurally
const graphics = this.make.graphics({ x: 0, y: 0, add: false });
const graphics = this.make.graphics({ x: 0, y: 0, });
graphics.fillStyle(0xffffff, 1);
graphics.fillCircle(8, 8, 8);
graphics.generateTexture('flare', 16, 16);

View file

@ -1,6 +1,6 @@
import Phaser from 'phaser';
import { UIButton } from '../objects/UIButton.js';
import { socket } from '@/lib/socket.js';
import * as Phaser from 'phaser';
import { UIButton } from '../objects/UIButton';
import { socket } from '@/lib/socket';
export class LobbyScene extends Phaser.Scene {
private tablesText: Phaser.GameObjects.Text[] = [];

View file

@ -1,5 +1,5 @@
import Phaser from 'phaser';
import { UIButton } from '../objects/UIButton.js';
import * as Phaser from 'phaser';
import { UIButton } from '../objects/UIButton';
interface ResultData {
matchId: string;
@ -71,7 +71,7 @@ export class ResultScene extends Phaser.Scene {
}
// Impact particles
const graphics = this.make.graphics({ x: 0, y: 0, add: false });
const graphics = this.make.graphics({ x: 0, y: 0, });
graphics.fillStyle(0xffffff, 1);
graphics.fillCircle(4, 4, 4);
graphics.generateTexture('resultSpark', 8, 8);

View file

@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"target": "ES2022",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@ -13,11 +17,24 @@
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }],
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
"@/*": [
"./src/*"
]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
"include": [
"**/*.ts",
"**/*.tsx",
"next-env.d.ts",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}

View file

@ -41,7 +41,7 @@ export interface MatchState {
winner?: string;
txHash?: string;
createdAt: number;
commitDeadline?: number;
commitDeadline: number;
revealDeadline?: number;
}

6465
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff