Passe Le Vol d'Icare en plein écran avec podium animé pour le top 3
Build and deploy / deploy (push) Successful in 35s

Le classement (dont un nouveau podium top 3, réutilisant celui de L'Agora)
vit maintenant dans une modale entièrement détachée de la mise en page du
jeu : une mise à jour Realtime du classement pendant une partie ne peut
plus redimensionner le canvas et casser la partie en cours. Le jeu occupe
tout l'écran disponible (contain avec letterboxing) au lieu d'une carte
fixe en haut de page. Corrige aussi le score du classement, en bleu au
lieu de doré (contraste insuffisant sur fond marbre clair).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Valentin ROBIN
2026-08-23 22:41:08 +02:00
parent e542b09807
commit 0dfd3e7e90
3 changed files with 121 additions and 73 deletions
+40 -31
View File
@@ -175,10 +175,19 @@ export function IcarusGame({ onFinish }: { onFinish: (score: number) => void })
const ctx = canvas.getContext("2d");
if (!ctx) return;
// "Contain" dans le conteneur (largeur ET hauteur, contrairement à avant
// où seule la largeur comptait) : nécessaire en plein écran, où la
// hauteur disponible varie et n'est plus déduite de la largeur.
function resize() {
const dpr = window.devicePixelRatio || 1;
const cssWidth = container!.clientWidth;
const cssHeight = cssWidth * (VIEWPORT_HEIGHT / VIEWPORT_WIDTH);
const availableWidth = container!.clientWidth;
const availableHeight = container!.clientHeight;
let cssWidth = availableWidth;
let cssHeight = (cssWidth * VIEWPORT_HEIGHT) / VIEWPORT_WIDTH;
if (cssHeight > availableHeight) {
cssHeight = availableHeight;
cssWidth = (cssHeight * VIEWPORT_WIDTH) / VIEWPORT_HEIGHT;
}
canvas!.width = cssWidth * dpr;
canvas!.height = cssHeight * dpr;
canvas!.style.width = `${cssWidth}px`;
@@ -283,38 +292,38 @@ export function IcarusGame({ onFinish }: { onFinish: (score: number) => void })
typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
return (
<div className="flex flex-col items-center gap-3">
<div
ref={containerRef}
onPointerDown={requestFlap}
className="relative w-full max-w-xs touch-none select-none overflow-hidden rounded-2xl border border-gold/40 shadow-xl"
>
<canvas ref={canvasRef} className="block h-full w-full" />
<div
ref={containerRef}
onPointerDown={requestFlap}
className="relative flex flex-1 touch-none items-center justify-center overflow-hidden bg-ink select-none"
>
<canvas ref={canvasRef} className="block" />
{status === "dead" && !prefersReducedMotion && <Confetti />}
{status === "dead" && (
<div className="absolute inset-0 flex items-center justify-center bg-ink/50">
<div className="marble-surface animate-reveal flex flex-col items-center gap-2 rounded-xl border border-gold/40 px-6 py-4 text-center shadow-lg">
<p className="text-xs tracking-wide text-text-mut uppercase">Score</p>
<p className="font-heading text-3xl text-gold-bright">{score}</p>
<button
type="button"
onPointerDown={(event) => event.stopPropagation()}
onClick={resetGame}
className="mt-1 rounded-md bg-ink-2 px-4 py-2 font-heading text-sm tracking-wide text-gold-bright uppercase transition hover:bg-ink"
>
Rejouer
</button>
</div>
</div>
)}
</div>
{status === "dead" && !prefersReducedMotion && <Confetti />}
{status === "idle" && (
<p className="text-center text-sm text-marble/60">
Touche l&apos;écran pour battre des ailes et t&apos;envoler entre les colonnes.
</p>
<div className="pointer-events-none absolute inset-x-0 bottom-10 flex justify-center px-6">
<p className="marble-surface animate-reveal rounded-lg border border-gold/40 px-4 py-2 text-center text-sm text-text-marble shadow-lg">
Touche l&apos;écran pour battre des ailes et t&apos;envoler entre les colonnes.
</p>
</div>
)}
{status === "dead" && (
<div className="absolute inset-0 flex items-center justify-center bg-ink/50">
<div className="marble-surface animate-reveal flex flex-col items-center gap-2 rounded-xl border border-gold/40 px-6 py-4 text-center shadow-lg">
<p className="text-xs tracking-wide text-text-mut uppercase">Score</p>
<p className="font-heading text-3xl text-gold-bright">{score}</p>
<button
type="button"
onPointerDown={(event) => event.stopPropagation()}
onClick={resetGame}
className="mt-1 rounded-md bg-ink-2 px-4 py-2 font-heading text-sm tracking-wide text-gold-bright uppercase transition hover:bg-ink"
>
Rejouer
</button>
</div>
</div>
)}
</div>
);