# Spam — données publiques des cartes / public card data

*Français d'abord — [English below](#english).*

Tout ce qu'il faut pour reconstruire les cartes **sorties** du jeu « Spam » : textes dans les 7 langues du jeu, statistiques, lore, illustrations et pièces du cadre. Ce sont de simples fichiers statiques, sans clé ni inscription, lisibles depuis un navigateur (CORS ouvert).

**Conditions d'utilisation : [spamgame.com/conditions-donnees-cartes](https://spamgame.com/conditions-donnees-cartes)** — usage de fan non commercial, crédit de l'artiste obligatoire, mention « projet non officiel ».

## Fichiers

Racine : `https://spamgame.com/data/`. Tous les chemins des fichiers (`img/...`) sont relatifs à cette racine.

| Fichier | Contenu |
|---|---|
| `index.json` | Point d'entrée : version la plus récente (`latest`), versions disponibles, langues, gabarit des chemins. |
| `latest/cards.<langue>.json` | Les cartes de la dernière version. Langues : `fr`, `en`, `es`, `pt` (Portugal), `pt-BR`, `it`, `de`. |
| `<version>/cards.<langue>.json` | Même chose, figée pour une version du jeu (ex. `1.19/`). Utile pour comparer l'équilibrage entre versions. |
| `layout.json` | Composition d'une carte (positions et tailles des pièces sur une carte de 961 × 1375). |
| `img/illustrations/{1024,512,128}/<slug>.<empreinte>.webp` | Illustrations, 3 hauteurs. Le nom change quand l'image change : elles peuvent être mises en cache sans limite. |
| `img/frame/*.webp`, `img/elements/*.webp`, `img/icons/*.webp`, `img/skills/*.webp` | Pièces du cadre, orbes d'élément, icônes de texte, icônes de tox. |
| `img/styles/**/<nom>.<empreinte>.webp` | Images des styles de carte (ornements animés, contours, textures). Comme les illustrations, le nom change avec l'image. |

Les JSON sont régénérés sous la même adresse : revalidez-les (`Cache-Control: no-cache`) plutôt que de les garder indéfiniment.

## `cards.<langue>.json`

```jsonc
{
  "schema": 1,                 // change si le format change de façon incompatible
  "version": "1.19",           // version du jeu
  "language": "fr",
  "generatedAt": "2026-09-18T18:27:24Z",
  "terms": "https://spamgame.com/conditions-donnees-cartes",
  "elements": [{ "id": "fire", "name": "Feu", "order": 1, "icon": "img/elements/fire.webp", "color": "#FC873E" }],
  "rarities": [{ "id": "common", "name": "Commune", "order": 1, "gem": "img/frame/rarity-common.webp", "textColor": "#9692A0" }],
  "keywords": [ /* glossaire des mots-clés cités dans les textes, voir plus bas */ ],
  "cards": [ /* voir ci-dessous */ ]
}
```

### Une carte

| Champ | Description |
|---|---|
| `id` | Identifiant stable (UUID). C'est aussi l'identifiant des cartes dans les données du jeu. |
| `slug` | Identifiant lisible et stable (`aidan`, `esprit_feu`). |
| `number` | Numéro d'ordre de la carte (stable ; il y a des trous : des cartes restent à sortir). |
| `name` | Nom dans la langue du fichier. |
| `element` | `fire`, `water`, `earth`, `nature`, `light`, `shadow` ou `divine` (affiché « Éther »). |
| `rarity` | `common`, `rare`, `epic`, `legendary` ou `divine`. |
| `spamton` | Spamtons générés par la carte (le chiffre sur l'hexagone doré). |
| `hp` | Points de vie. |
| `resistances` | Résistance par élément, en % : 11 = 11 % de dégâts en moins, négatif = faiblesse. |
| `artwork` | `file` (1024 px de haut), `small` (512), `tiny` (128), `width`/`height` (taille de `file`), `artist` (`name`, `link`) — **à créditer**. |
| `abilities` | Compétences (capacités actives), dans l'ordre de la carte. |
| `skills` | Tox (passifs) de la carte, avec leur `rarity` (`common`→`legendary`). |
| `talents` | Les 3 talents de la carte (`slot` 1 à 3), choisis dans le deck. Ils n'apparaissent pas sur la carte. |
| `lore` | `species`, `region`, `era`, `text` — ou `null`. |
| `styles` | Les styles de la carte, comme dans le jeu : `cardstyle-standard`, `cardstyle-elementary`, `cardstyle-fullart` (toutes les cartes), puis ses arts alternatifs. Un id absent des `styles` du document n'est pas publié (aucune image). Voir [Styles de carte](#styles-de-carte). |

### Compétences, tox, talents

Champs communs : `id` (stable), `name`, `effect`, `effectRich`.

Compétences seulement : `cooldown` (tours de recharge, le chiffre dans l'anneau), `elements` (éléments en jeu), `precision` (% de toucher), `critChance` (% de critique, 0 si la compétence ne peut pas critiquer), `critMultiplier`, `duration`, `uses` (usages limités, 0 = illimité), `cooldownResetChance` (%), `actions`.

Tox seulement : `rarity`, `element`, `value` (valeur du tox), `icon`.

Talents seulement : `elements`, `grantsSkill` (id du tox donné par le talent, ou `null`), `actions`.

`actions` : les effets bruts, dans l'ordre, y compris ceux des capacités enchaînées (`chain` = 0 pour la capacité elle-même, n pour la n-ième capacité enchaînée : coup supplémentaire, option d'un choix…). `kind` vaut `damage`, `heal` ou `other` ; `min`/`max` sont les bornes de la valeur ; `percent: true` signale une valeur en pourcentage (des PV) et non en points ; `element` vaut `null` pour une action sans élément ou, pour des dégâts, un élément tiré au hasard.

### Textes : `effect` et `effectRich`

Les textes sont ceux que le jeu affiche hors partie (valeurs de base, sans bonus de partie). Seule différence : un usage limité s'écrit à son compteur de début de partie (« [Usage Limité 1/1] »).

- `effect` : le même texte sans jeton ni balise (« Attaque 30 Feu »).
- `effectRich` : comme en jeu, avec des jetons à remplacer par vos icônes et infobulles :
  - `{icon:fire}` … `{icon:shadow}` : icône d'élément — images dans `img/elements/` ;
  - `{el:fire}Feu{/el}` : le nom de l'élément, écrit juste après son icône dans la couleur `color` de l'élément ;
  - `{icon:crit}`, `{icon:precision}` : icônes de critique et de précision — `img/icons/` ;
  - `{kw:<id>}texte{/kw}` : mot-clé ; `id` désigne l'entrée de `keywords` que le jeu ouvre POUR CETTE occurrence — un même mot peut renvoyer à des entrées différentes selon la capacité qui le porte (« Vampirisme » dans une capacité qui porte `Life Steal_R` ouvre ce tox-là, avec ses 50 %). Le texte entre les jetons est déjà celui du jeu : quand le mot désigne exactement un panneau, le jeu y écrit le titre de ce panneau (« Dégâts de zone II » s'affiche « AoE »).

Expression régulière utile : `/\{icon:([a-z]+)\}|\{kw:([^}]+)\}(.*?)\{\/kw\}/g`. Les sauts de ligne sont des `\n`.

### `keywords`

`{ "id": "stun", "title": "Étourdissement", "description": "…", "descriptionRich": "…" }` : ce que le jeu affiche au survol du mot. Les `id` en `tox.`, `talent.` et `ability.` désignent une capacité précise : leur entrée reprend son vrai titre et son texte avec ses valeurs (un talent qui donne un tox affiche ce tox). Le glossaire contient les mots-clés des textes du fichier et ceux que citent ses propres entrées. `description` peut être `null`.

`tooltip` dit quelle infobulle le jeu montre : `glossary` (titre + règle), `passive` (un tox : ligne de tox aux traits et à l'aura de sa `rarity`, qui peut être `null`, puis le texte), `active` (une attaque : `ability` donne `cooldown`, `elements`, `precision`, `critChance`, `critMultiplier`, comme les capacités des cartes) ou `currency` (une monnaie, que `currency` identifie : son icône, son nom et sa règle, sans le revenu du compteur).

`decoration` dit comment le jeu ÉCRIT le mot dans le texte : `color` (la couleur de la rareté du tox désigné, celle de l'élément pour une attaque, `#FFFF59` sinon), `ornament` (les deux moitiés de la bande de rareté posées de part et d'autre du mot — la moitié gauche avant, la droite après, chacune à deux fois et demie la largeur d'une icône de texte) et `icon` (`{ src, spaced }` : l'image posée devant le mot — celle de l'élément d'une attaque ou de la monnaie, collée au mot ; celle du mot lui-même, critique ou précision, suivie d'une espace quand `spaced` est vrai). `ornament` et `icon` sont absents quand il n'y en a pas.

## Reconstruire une carte : `layout.json`

Les cotes sont en pixels d'une carte de **961 × 1375** : multipliez-les par `largeur affichée / 961`. Dans l'ordre d'empilement (celui du jeu) :

1. `artwork` : l'illustration, en `cover`, alignée en haut, coins arrondis `cornerRadius`.
2. `body` : le corps de l'élément de la carte (`img/frame/body-{element}.webp`), de la taille de la carte.
3. `header` : voile en dégradé derrière le nom ; `name` : le nom, centré, 2 lignes au plus.
4. `border` : bordure noire intérieure.
5. `elementOrb`, puis `rarityGem` : ils débordent de la carte.
6. `rows` : une ligne par compétence puis par tox, de haut en bas (`top + i * step`, `max` lignes).
   - compétence : `bar` (image noircie à 30 %), `cooldown` (anneau, mélange *overlay*), `cooldownText`, `name` ;
   - tox : l'image `skill-line-{rarity}` coupée en deux, moitié gauche en `lineLeft` et moitié droite en `lineRight`, nom au centre.
7. `hpBar` : barre de vie et texte `hp/hp`.
8. `spamton` (+ son chiffre).

C'est le style Standard ; les autres styles changent certains calques (section suivante). Police : [Lilita One](https://fonts.google.com/specimen/Lilita+One) (SIL OFL). La galerie SpamDex du site est construite exactement ainsi.

<a id="styles-de-carte"></a>

## Styles de carte : `styles` et `styleEffects`

Le document décrit chaque style publié dans `styles` (dans l'ordre du jeu) :

| Champ | Description |
|---|---|
| `id`, `name`, `order` | Identifiant (celui des `styles` des cartes), nom affiché par le jeu, ordre. |
| `alternative` | `true` pour un art alternatif : seulement sur les cartes qui le listent. |
| `renamesCard` | Le jeu écrit le nom du style à la place de celui de la carte. |
| `artist` | Artiste du style (`name`, `link`) — **à créditer** comme celui d'une illustration. |
| `artwork` | Illustration propre au style (`file`, `width`, `height`), qui remplace celle de la carte ; sinon `null`. |
| `thumbnail` | Image fixe du style (vignette de la boutique du jeu), ou `null`. |
| `elements.<element>` | Les calques du style pour une carte de cet élément : `panel` (le corps, un chemin d'image ; `null` = aucun corps, l'illustration couvre toute la carte), puis `illustration`, `outline`, `front`, `back` : un identifiant de `styleEffects`, ou `null`. |

`styleEffects` contient les recettes, par identifiant. Toutes les boîtes (`box`) sont en unités de `layout.json` et peuvent déborder de la carte ; `sizes.large` est à la résolution du jeu sur PC, `sizes.small` suffit pour une galerie, `still` est la première image (pour qui réduit les animations).

- **`frames`** — ornement image par image (cartes Élémentaires) : un WebP animé qui contient la boucle complète, à poser dans `box`. `layer` dit où : `Card Front Animated` au-dessus de l'orbe d'élément et sous la gemme, les lignes et la barre de vie ; `Card Back Animated` derrière toute la carte.
- **`glowOutline`** — contour lumineux, posé dans `box` (la carte à l'échelle 1,04 × 1,03) au-dessus de l'illustration, du corps et du nom, sous l'orbe. Une carte qui en a un n'a pas la bordure noire.
  - `mode: "rainbow"` : l'image `colors` (les couleurs telles qu'affichées), étirée sur `box` et répétée en largeur, défile vers la gauche d'une largeur de `box` toutes les `period` secondes, découpée par l'alpha de l'image `mask`.
  - `mode: "gradient"` : boucle précalculée (`sizes`) d'une durée `period` ; `colorTop` et `colorBottom` sont ses deux couleurs si un rendu fixe vous suffit.
  - `mode: "solid"` : la couleur `color` découpée par `mask`.
- **`animatedFullArt`** — illustration animée par calques (art alternatif de la Maîtresse des Teintes) : les paramètres du shader du jeu, `textures` (`srgb: true` = à décoder en linéaire ; `default` = texture par défaut du shader), `floats`, `vectors` et `colors` (sRGB tels qu'enregistrés ; le jeu les linéarise). Le jeu compose en espace linéaire. La galerie SpamDex rejoue ce shader en WebGL ; sans lui, affichez le `thumbnail` du style.

En résumé : **Standard** = corps de l'élément ; **Élémentaire** = corps + ornement animé (`front`, et `back` pour la Terre) + contour bicolore (l'Éther n'a ni l'un ni l'autre) ; **Full Art** = pas de corps, l'illustration nue sur toute la carte, contour arc-en-ciel ; un **art alternatif** remplace en plus l'illustration.

## Exemple

```js
const base = 'https://spamgame.com/data/'
const index = await (await fetch(base + 'index.json')).json()
const data = await (await fetch(base + `${index.latest}/cards.fr.json`)).json()
for (const card of data.cards) {
  console.log(card.number, card.name, card.hp, base + card.artwork.small, card.artwork.artist?.name)
}
```

## Versions du format

- `schema` 1 — 18/09/2026 : première publication. Le même jour : `styles` d'une carte liste tous ses styles (il ne listait que ses arts alternatifs), et les documents gagnent `styles` et `styleEffects`.
- 19/09/2026 : les recettes `animatedFullArt` suivent les paramètres PAR EFFET du shader du jeu. Pour chaque emplacement (`_Base`, `_L1`…`_L4`) et chaque effet (`Float`, `Distort`, `Flow`, `Advect`) : `<emplacement>_<effet>_Amplitude`, `_Speed` et `_MaskInfluence` (dosage 0-1 qui remplace l'interrupteur `_Masked`), plus `_NoiseScale` pour `Distort` et `Flow` et `_NoiseScroll` pour `Distort` (ex. `_L2_Float_Amplitude`). Disparaissent : `<emplacement>_Amplitude`, `_Speed`, `_NoiseScale`, `_NoiseScroll`, `_NoiseInfluence`, les `_<effet>_Intensity` et `_<effet>_MaskDosesNoise` ; `_Glow_Masked` devient `_Glow_MaskInfluence`. `schema` inchangé.

Une question, une erreur dans les données : **support@spamgame.com**.

---

<a id="english"></a>

## English

Everything needed to rebuild the **released** cards of the game "Spam": texts in the game's 7 languages, statistics, lore, illustrations and card frame parts. Plain static files, no key or sign-up, readable from a browser (CORS enabled).

**Terms of use: [spamgame.com/conditions-donnees-cartes](https://spamgame.com/conditions-donnees-cartes)** — non-commercial fan use, artist credit required, "unofficial project" notice.

- Root: `https://spamgame.com/data/`; every `img/...` path is relative to it.
- `index.json`: entry point (`latest` version, available versions, languages, path template).
- `latest/cards.<lang>.json` and `<version>/cards.<lang>.json` (frozen per game version): `fr`, `en`, `es`, `pt` (Portugal), `pt-BR`, `it`, `de`.
- `layout.json`: card composition on a 961 × 1375 card, bottom layer first (see the French section above for the layer list, in game order: artwork, body, header and name, border, element orb, rarity gem, rows, HP bar, Spamton).
- Illustrations: `img/illustrations/{1024,512,128}/<slug>.<hash>.webp` and style images `img/styles/**/<name>.<hash>.webp` — the name changes when the image changes, so they can be cached forever. JSON files are regenerated in place: revalidate them.

Card fields: `id` (stable UUID), `slug`, `number` (stable order, with gaps for unreleased cards), `name`, `element` (`divine` is shown as "Ether"), `rarity`, `spamton` (Spamtons generated per turn), `hp`, `resistances` (% per element, negative = weakness), `artwork` (`file`/`small`/`tiny`, `artist` — **credit required**), `abilities` (active abilities), `skills` (toxs = passives, with a `rarity`), `talents` (the 3 deck-builder talents, not drawn on the card), `lore`, `styles` (the card's styles as in game: `cardstyle-standard`, `cardstyle-elementary`, `cardstyle-fullart` for every card, then its alternative arts; an id missing from the document's `styles` is not published).

Card styles: the document's `styles` lists each published style (`name` as shown in game, `alternative`, `artist` — **credit required**, `artwork` replacing the card illustration, `thumbnail`) and, per element, its layers: `panel` (body image, `null` = no body, the illustration covers the card) and `illustration` / `outline` / `front` / `back` ids of `styleEffects` recipes. Boxes are in `layout.json` units and may overflow the card; `sizes.large` is the game's PC resolution, `sizes.small` is enough for a gallery, `still` is the first frame. Recipes: `frames` (animated WebP of the full loop; `Card Front Animated` goes above the element orb and below the gem, rows and HP bar, `Card Back Animated` behind the whole card), `glowOutline` (above the card face and name, below the orb; no black border then — `rainbow`: `colors` stretched over `box`, repeated horizontally, scrolling left by one `box` width every `period` seconds, clipped by the alpha of `mask`; `gradient`: precomputed loop in `sizes`; `solid`: `color` clipped by `mask`), `animatedFullArt` (the game's layered shader parameters: `textures` with `srgb`, `floats`, `vectors`, `colors`; composed in linear space — the SpamDex gallery replays it in WebGL, otherwise show the style `thumbnail`). Standard = element body; Elementary = body + animated ornament + two-color outline (none for Ether); Full Art = no body, plain illustration over the whole card, rainbow outline; an alternative art also replaces the illustration.

Abilities: `cooldown`, `elements`, `precision` (%), `critChance` (%, 0 when the ability cannot crit), `critMultiplier`, `duration`, `uses` (0 = unlimited), `cooldownResetChance` (%), `actions` (raw effects including chained abilities: `chain` 0 = the ability itself; `kind` = `damage` / `heal` / `other`; `percent: true` = the value is a percentage, not points; `element: null` = no element or, for damage, a random element).

Texts are the ones the game shows outside a match. `effect` is plain text with element names spelled out; `effectRich` uses tokens: `{icon:fire}`…`{icon:shadow}` (element icon, the game hides the name), `{icon:crit}`, `{icon:precision}`, and `{kw:<id>}text{/kw}` for keywords, whose tooltips are in `keywords` (same `id`; `tox.`, `talent.` and `ability.` ids show the actual ability with its real values, as in game; `tooltip` tells which tooltip the game shows: `glossary` = title + rule, `passive` = a tox, drawn as a tox row with the lines and aura of its `rarity` (may be `null`), `active` = an attack whose `ability` gives `cooldown`, `elements`, `precision`, `critChance`, `critMultiplier` like card abilities). A keyword `id` is the entry the game opens FOR THAT occurrence: the same word can point to different entries depending on the ability carrying it, and the text between the tokens is already what the game writes (the title of the panel it opens, when the word matches it exactly). `decoration` says how the word is written: `color`, `ornament` (both halves of the rarity band, placed before and after the word, each two and a half times the width of an inline icon) and `icon` (`{ src, spaced }`: the image before the word — an element or currency icon glued to it, or the word's own icon followed by a space when `spaced`). `tooltip` can also be `currency`, for a named currency (`currency` gives its id). `{el:fire}Fire{/el}` marks an element name, written next to its icon in the element's `color`. Elements carry their `color` and rarities their `textColor`. Useful regex: `/\{icon:([a-z]+)\}|\{kw:([^}]+)\}(.*?)\{\/kw\}/g`.

Format changes: 18/09/2026, first release (`schema` 1). 19/09/2026: `animatedFullArt` recipes follow the game shader's per-effect parameters: for each slot (`_Base`, `_L1`…`_L4`) and effect (`Float`, `Distort`, `Flow`, `Advect`), `<slot>_<effect>_Amplitude`, `_Speed` and `_MaskInfluence` (0–1 amount replacing the `_Masked` switch), plus `_NoiseScale` for `Distort` and `Flow` and `_NoiseScroll` for `Distort` (e.g. `_L2_Float_Amplitude`); the per-slot `_Amplitude`, `_Speed`, `_NoiseScale`, `_NoiseScroll`, `_NoiseInfluence` and the `_<effect>_Intensity` and `_<effect>_MaskDosesNoise` values are gone, and `_Glow_Masked` becomes `_Glow_MaskInfluence`. `schema` unchanged. 21/09/2026: keywords carry `decoration`, elements a `color` and rarities a `textColor`; a keyword token now names the entry the game opens for that occurrence, and the highlighted text may be the panel title rather than the writer wording. Same day, later: the game always writes an element's name next to its icon (new `{el:<id>}…{/el}` token, and `effect` spells the localized name), currencies became keywords (`tooltip: "currency"`), keyword icons moved in front of the word (`decoration.icon` is now an object) and keyword colours are lightened to a readability floor. `schema` unchanged.

Font: [Lilita One](https://fonts.google.com/specimen/Lilita+One) (SIL OFL). Questions or data errors: **support@spamgame.com**.
