Passe de polish visuel sur tout le site
Corrige deux incohérences trouvées en chemin : le compteur de passages dans le char en gold-bright sur marbre (même défaut de contraste déjà vu ailleurs), et le point du Crieur toujours rouge même pour un honneur positif. Réutilise les ornements existants mais jamais appelés (meander-divider entre le podium et le classement, DiamondDivider sur /profile avec une nouvelle convention de carte secondaire). Ajoute une ambiance discrète (fond qui respire très lentement, halo doré sur les cartes marbre, désactivés sous prefers-reduced-motion), étend les confettis et un nouveau son à Icare pour la parité avec la Corne d'Abondance, des loading.tsx sur les pages les plus consultées, et un petit ornement sur les états vides plutôt qu'un texte brut. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,11 +43,11 @@ import {
|
||||
stepIcarus,
|
||||
} from "@/lib/icarus/physics";
|
||||
import type { Boost, Column, IcarusState, ShatterEffect } from "@/lib/icarus/types";
|
||||
import { playBoostSound } from "@/lib/icarus/sound";
|
||||
import { Confetti } from "@/components/confetti";
|
||||
|
||||
type Status = "idle" | "flying" | "dead";
|
||||
|
||||
const CONFETTI_COLORS = ["#E7C560", "#C9A227", "#F4ECD8", "#A5342A", "#5E6B3B", "#2E6E7E", "#B08D57"];
|
||||
|
||||
// 0 avant DIFFICULTY_START_SCORE, monte jusqu'à 1 sur DIFFICULTY_RAMP_SPAN
|
||||
// points, puis reste à 1 (palier, pour ne pas devenir injouable).
|
||||
function difficultyProgress(score: number): number {
|
||||
@@ -499,6 +499,7 @@ export function IcarusGame({
|
||||
const collectedIndex = boostsRef.current.findIndex((b) => collidesWithBoost(icarusRef.current.y, b));
|
||||
if (collectedIndex !== -1) {
|
||||
boostsRef.current.splice(collectedIndex, 1);
|
||||
playBoostSound();
|
||||
// Active le bouclier pour les N prochaines colonnes (distance
|
||||
// aléatoire, voir plus bas) et déclenche l'animation de bond en
|
||||
// avant. Icare se fige (vitesse verticale annulée, plus de
|
||||
@@ -637,56 +638,6 @@ export function IcarusGame({
|
||||
);
|
||||
}
|
||||
|
||||
type ConfettiPiece = {
|
||||
id: number;
|
||||
left: number;
|
||||
color: string;
|
||||
delay: number;
|
||||
duration: number;
|
||||
spin: number;
|
||||
drift: number;
|
||||
};
|
||||
|
||||
function generateConfettiPieces(): ConfettiPiece[] {
|
||||
return Array.from({ length: 26 }, (_, index) => ({
|
||||
id: index,
|
||||
left: Math.random() * 100,
|
||||
color: CONFETTI_COLORS[index % CONFETTI_COLORS.length],
|
||||
delay: Math.random() * 250,
|
||||
duration: 900 + Math.random() * 700,
|
||||
spin: (Math.random() > 0.5 ? 1 : -1) * (360 + Math.random() * 360),
|
||||
drift: (Math.random() - 0.5) * 70,
|
||||
}));
|
||||
}
|
||||
|
||||
function Confetti() {
|
||||
// Initialiseur paresseux de useState (n'exécute Math.random() qu'une
|
||||
// seule fois, au montage — Confetti est remonté à chaque nouvelle partie
|
||||
// terminée) plutôt qu'un appel impur dans le corps du composant.
|
||||
const [pieces] = useState(generateConfettiPieces);
|
||||
|
||||
return (
|
||||
<div className="pointer-events-none absolute inset-0 overflow-hidden">
|
||||
{pieces.map((piece) => (
|
||||
<span
|
||||
key={piece.id}
|
||||
className="animate-confetti-fall absolute top-0 h-2.5 w-1.5 rounded-[1px]"
|
||||
style={
|
||||
{
|
||||
left: `${piece.left}%`,
|
||||
backgroundColor: piece.color,
|
||||
animationDelay: `${piece.delay}ms`,
|
||||
animationDuration: `${piece.duration}ms`,
|
||||
"--confetti-spin": `${piece.spin}deg`,
|
||||
"--confetti-drift": `${piece.drift}px`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function render(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
canvas: HTMLCanvasElement,
|
||||
|
||||
Reference in New Issue
Block a user