Aller au contenu

Architecture

Arborescence

RandomDeadlock/
├── index.html              # page HTML d'entrée (div#root + /src/main.jsx)
├── vite.config.js          # plugins Tailwind + React SWC, serveur de dev
├── eslint.config.js        # configuration ESLint « flat »
├── package.json            # scripts et dépendances (npm, package-lock.json)
├── public/                 # copié tel quel à la racine du site
│   ├── Deadlock_Render_Heroes/   # images en grand des héros
│   ├── deadlockCards/            # cartes miniatures (grille)
│   ├── deadlockTypo/             # noms stylisés
│   └── vite.svg                  # favicon (celui du template Vite)
└── src/
    ├── main.jsx            # monte <App /> dans #root, en StrictMode
    ├── App.jsx             # toute l'application
    ├── index.css           # @import "tailwindcss" + @plugin "daisyui"
    └── assets/react.svg    # reste du template, non utilisé

Toute la logique tient dans src/App.jsx, qui contient un seul composant.

Composant App

État

Variable Initialisation Rôle
heroLists useState([...]) Liste en dur des 32 héros, sous forme d'objets { name: "..." }. Elle n'a pas de setter, donc elle ne change jamais.
choosedHero useState(null) Héros actuellement tiré
reset useState(false) Booléen inversé à chaque clic. Il sert uniquement à relancer l'effet de tirage.

Logique de tirage

src/App.jsx
useEffect(() => {
  const randomIndex = Math.floor(Math.random() * heroLists.length)
  setChoosedHero(heroLists[randomIndex])
}, [reset])
  • L'index est uniforme entre 0 et heroLists.length - 1.
  • Le bouton exécute setReset(!reset). La dépendance de l'effet change, ce qui provoque un nouveau tirage.
  • Tant que choosedHero vaut null (au tout premier rendu), le composant affiche Chargement....
flowchart TD
  A[Montage de App] --> B["useEffect : index = random × 32"]
  B --> C[setChoosedHero]
  C --> D[Rendu : grille + image du héros + nom + bouton]
  D -->|clic « Choisir à nouveau »| E["setReset(!reset)"]
  E --> B

StrictMode en développement

main.jsx enveloppe l'application dans <StrictMode>. En dev, React exécute alors l'effet deux fois au montage, ce qui fait deux tirages d'affilée. Le résultat n'est pas visible à l'écran et ce double appel n'existe pas en production.

Rendu

Zone Classes principales Contenu
Conteneur flex max-h-screen bg-black text-white Disposition en deux colonnes
Grille (gauche) grid grid-cols-2 md:grid-cols-4 w-1/3 overflow-y-auto Une carte de 88×119 px par héros, dans l'ordre de heroLists, avec le nom en surimpression (bg-black/50)
Héros tiré (droite) flex-1, image h-screen object-contain Image du héros en grand, puis par-dessus, en position absolue : l'image du nom et le bouton daisyUI btn btn-primary

Assets

Les images se trouvent dans public/. Vite les sert à la racine du site (/deadlockCards/...) et les copie telles quelles dans dist/ au moment du build.

Dossier Usage Nom de fichier Format
public/Deadlock_Render_Heroes/ Image en grand du héros tiré {Nom}_Render.png PNG de 1112 à 2080 px de large et 1024 à 1440 px de haut, 1 à 2,9 Mo chacun (≈ 72 Mo au total)
public/deadlockCards/ Cartes de la grille 88px-{Nom}_card.png PNG 88×119 px
public/deadlockTypo/ Nom stylisé du héros tiré 120px-{Nom}_name.png PNG de 120 px de large, hauteur variable

Chaque dossier contient 32 fichiers, un par héros de heroLists.

Convention {Nom}

{Nom} correspond au champ name du héros, dont chaque suite d'espaces est remplacée par _ (name.replace(/\s+/g, '_')). Tout le reste est conservé : majuscules, &, accents.

name dans heroLists {Nom} Fichier de carte
Abrams Abrams 88px-Abrams_card.png
Grey Talon Grey_Talon 88px-Grey_Talon_card.png
Mo & Krill Mo_&_Krill 88px-Mo_&_Krill_card.png
The Doorman The_Doorman 88px-The_Doorman_card.png

Fichier manquant ou mal nommé

  • Pour les cartes et l'image en grand, un handler onError masque l'image (display: none) : aucune erreur n'apparaît, le héros s'affiche simplement sans image.
  • L'image du nom n'a ni onError ni alt. Si elle manque, le navigateur affiche une icône d'image cassée.
  • En production (Linux), les noms de fichiers sont sensibles à la casse.

Ajouter un nouveau héros

Exemple avec un héros fictif nommé Nouveau Heros :

  1. Préparer les 3 images, nommées selon la convention :

    public/Deadlock_Render_Heroes/Nouveau_Heros_Render.png
    public/deadlockCards/88px-Nouveau_Heros_card.png      # 88×119 px
    public/deadlockTypo/120px-Nouveau_Heros_name.png      # 120 px de large
    
  2. Déclarer le héros dans heroLists (src/App.jsx). Sa position dans le tableau fixe sa place dans la grille :

    src/App.jsx
    { name: "Mina" }, { name: "Drifter" }, { name: "Victor" }, { name: "Paige" },
    { name: "Nouveau Heros" }
    
  3. Vérifier en local avec npm run dev (Développement) : la carte doit apparaître dans la grille, et l'image en grand ainsi que le nom doivent s'afficher quand le héros est tiré.

  4. Pousser sur main : Dokploy redéploie automatiquement (Déploiement).

Caractères à éviter dans name

Le nom sert tel quel dans l'URL de l'image. Évitez #, ? et % : # et ? couperaient l'URL et % serait lu comme le début d'un encodage. Les espaces sont acceptés, puisqu'ils sont convertis en _.

Limites connues

  • Liste en dur : les héros sont codés dans App.jsx et doivent rester synchronisés à la main avec les trois dossiers d'images.
  • Images en grand lourdes : chaque tirage charge un PNG de 1 à 3 Mo. Les convertir en WebP ou AVIF réduirait nettement le poids.
  • Tirages consécutifs identiques possibles, car rien n'exclut le héros précédent.
  • Dépendances de l'effet : heroLists est utilisé dans le useEffect mais absent de son tableau de dépendances. Sans conséquence ici, puisque la liste ne change jamais, mais la règle react-hooks/exhaustive-deps le signale normalement.