Skip to content
← 1001 Widgets
N° 043 · ●●●

Real One Piece booster

A real One Piece booster: pick a set, tear open the pack, and ten official cards come out of the Poneglyph API, rarities drawn at random. The right exercise to combine an API, weighted randomness and animations.

JSAPI
What you'll learn
  • Chain two calls to a public API
  • Draw cards by rarity slot
  • Plan a fallback when the API does not answer
Why this language

Pourquoi un booster One Piece ? Le booster de base tire des raretés au hasard sur des cartes inventées. Ici, les cartes sont les vraies, servies par Tanuki Poneglyph, une API gratuite qui republie les données du jeu de cartes One Piece.

D'abord on charge la liste des sets, puis les cartes du set choisi. Un vrai paquet n'est pas tiré n'importe comment : six communes, trois peu communes, et un emplacement rare qui peut devenir super rare ou secret. Parfois, une version alternative se glisse dans le lot.

Si l'API ne répond pas, un set de démonstration prend le relais pour que la démo reste jouable.

Pourquoi en JavaScript simple ? Deux fetch, un tirage par emplacement et des animations CSS. Données issues du site officiel de Bandai. One Piece est une marque de Bandai, Toei Animation et Eiichiro Oda, et ce projet n'est pas affilié à Bandai.

How it works
  1. L'API

    const API = 'https://tanuki-poneglyph.pages.dev';
    const json = url => fetch(url).then(r => { if (!r.ok) throw new Error(r.status); return r.json(); });
  2. LES SETS, PUIS LES CARTES D'UN SET

    On accepte un tableau direct ou un objet qui le contient : l'API peut évoluer.

    const liste = (d, cles) => Array.isArray(d) ? d : cles.map(k => d?.[k]).find(Array.isArray) || [];
    const sets = liste(await json(`${API}/v1/sets.json`), ['sets', 'data']);
    const cartes = liste(await json(`${API}/v1/sets/${sets[0].set_id}.json`), ['cards', 'data']);
  3. PIOCHER DANS UNE RARETÉ

    Si la rareté manque dans ce set, on pioche dans tout le set plutôt que de planter.

    function pioche(raretes, deja) {
      let pool = cartes.filter(c => raretes.includes(c.rarity) && !c.version && !deja.includes(c));
      if (!pool.length) pool = cartes.filter(c => !deja.includes(c));
      return pool[Math.floor(Math.random() * pool.length)];
    }
  4. UN PAQUET

    Six communes, trois peu communes, et un emplacement rare tiré au sort.

    function paquet() {
      const p = [];
      for (let i = 0; i < 6; i++) p.push(pioche(['C'], p));
      for (let i = 0; i < 3; i++) p.push(pioche(['UC'], p));
      const r = Math.random();
      p.push(pioche(r < 0.025 ? ['SEC'] : r < 0.23 ? ['SR'] : ['R'], p));
      return p;
    }
  5. AFFICHER UNE CARTE

    Le champ image est un chemin : on le colle derrière l'adresse de l'API.

    function image(carte) {
      const img = new Image();
      img.loading = 'lazy';
      img.alt = `${carte.name} ${carte.card_number}`;
      img.src = API + carte.image;
      return img;
    }
Pitfalls

PIÈGE 1 : Supposer la forme de la réponse

Pitfall

Mauvais : data.cards.map(...) sans vérifier. Le jour où l'API renvoie un tableau direct, tout plante.

Fix

Correct : une petite fonction qui accepte les deux formes, et un message si la liste est vide.

PIÈGE 2 : Un tirage uniforme

Pitfall

Mauvais : dix cartes au hasard dans tout le set. Comme il y a beaucoup de communes et peu de rares, on ouvre des paquets sans intérêt, ou au contraire trop généreux.

Fix

Correct : des emplacements par rareté, comme dans un vrai paquet, avec des probabilités pour l'emplacement rare.

PIÈGE 3 : Charger toutes les images d'un coup

Pitfall

Mauvais : afficher les centaines d'images d'un set dès son chargement.

Fix

Correct : ne créer que les dix images du paquet, avec loading="lazy", au moment de l'ouverture.

PERSONNALISER
  • Une collection : les cartes ouvertes s'ajoutent à un classeur gardé dans localStorage.
  • Des probabilités différentes selon le type de set, booster ou deck de départ.
  • Un compteur de paquets ouverts avant la première carte secrète.
OPTIMISATION
  • Gardez la liste des sets en cache une journée : elle change rarement.
  • Préchargez les images du paquet pendant l'animation du sachet, avec new Image().
VERS REACT

Les sets et les cartes se chargent dans un useEffect, ou avec TanStack Query qui gère cache et erreurs.

Le paquet ouvert est un useState ; chaque carte garde son état retourné ou non.

L'animation du sachet se déclenche en ajoutant une classe, et le tirage s'affiche à la fin de la transition.

Comments
0/1000

Loading comments…

Audience measurement

With your consent, this site measures its traffic with Google Analytics and the Meta pixel, via Google Tag Manager. Nothing is loaded until you choose, and you can change your mind at any time with the "Cookies" link at the bottom of the page.