# TrySolitaire card decks

Two playing-card decks and three card backs, drawn from scratch for
[trysolitaire.com](https://trysolitaire.com) and released under
**CC BY 4.0** — use them, sell them, remix them, just credit the source.
See [`LICENSE.txt`](./LICENSE.txt) for the exact scope.

## Why these exist

Open playing-card art is dominated by two sets — *Vectorized Playing
Cards* and David Bellot's *SVG-cards* — and both are LGPL, which is
awkward to carry into a commercial game. Between them they also leave
two gaps that we kept running into:

- **Every open deck is white or cream.** There was no deck that belonged
  on a dark table.
- **Suit identity rests entirely on red-vs-black** — the one distinction
  a person with deuteranopia or protanopia cannot make.

So: one dark deck, one four-colour deck, permissively licensed.

| | |
|---|---|
| **Noir** | Dark-bodied deck. Suit colour keeps the two-way split a normal deck has, inverted in value — warm rose for hearts/diamonds, cool ivory for spades/clubs. |
| **Four Color** | Bridge-style. Spades slate, hearts red, diamonds blue, clubs green — values solved against CIEDE2000 under two dichromat models; see `LICENSE.txt`. |
| **Noir Mobile** | Noir in the mobile layout below. |
| **Four Color Mobile** | Four Color in the mobile layout below. |
| **Obsidian** | Dark card back: graphite argyle under a brass frame. |
| **Emerald** | Green card back, for green-felt tables. |
| **Ivory Deco** | Light, warm card back — art-deco sunburst. |

### The mobile layout

A card on a phone is drawn 32–60px wide, and a solitaire tableau overlaps
face-up cards at 20% of their height (`Utils.getMaxFaceUpOffset`) — so
for every card but the last in a column, all you ever see is a strip
about 60×17px, or 32×9px at the small end. The standard layout puts
eleven things in that space. The mobile layout puts three, each several
times larger:

- **one** corner index, not two. The 180°-rotated copy costs a third of
  the card for a redundancy that only pays off holding a physical hand.
- the rank runs 1.97× the desktop rank in height — 3.87× the ink area —
  and is aligned so every rank's leftmost ink lands on the same margin.
  (That is ink-left, not stem-left: on a `J` the hook reaches the margin
  and the stem sits inboard of it, which is what optical alignment
  means and what it looks like.)
- no pip grid. A ten drawn as ten pips is ten specks at this size; drawn
  as one large pip it reads instantly, and the rank glyph carries the
  count.

Courts stack an emblem over the suit pip. NotoSerif draws courts exactly
like number cards, so its queen of clubs and three of clubs differ only
in the corner letter. LargeSimple, MobileSimple and SerifFaces do ship
portrait court art — but at 46px those portraits are unresolvable, and
you cannot tell their J from their Q from their K either. An emblem is
the only one of the three that still carries court rank at phone sizes.

## What's in the box

```
Noir/AS.svg           vector source, self-contained (no font needed)
Noir/AS@1x.webp       160x224
Noir/AS@1.5x.webp     240x336
Noir/AS@2x.webp       320x448
```

52 cards per deck, named `<rank><suit>` with `T` for ten and suits as
`S H D C` — `AS`, `TC`, `QH`. Card backs live in `../cardBacks/` at
160x217 / 240x326 / 480x651.

The SVGs are the real source. The WebPs are what our app ships, so
they're the only part deployed to the site — if you need other sizes or
want to recolour, take the vectors from the repository:

<https://github.com/mallya/trysolitaire/tree/main/assets/cards>

## Regenerating

```
node scripts/generate-card-art.js            # everything
node scripts/generate-card-art.js Noir       # one deck or back
```

Reproduces every file byte-for-byte. The generator is a single
dependency-light script (`sharp` only) and is commented with the
reasoning behind the numbers that aren't obvious — per-suit optical
metrics, why the dark deck's rim is 4 units and not 2, and why card
backs and faces use different `@2x` widths.

## Design notes worth knowing before you modify

- **Pips are scaled through per-suit optical metrics, not one factor.**
  The four outlines don't share a bounding box — a club is 928 units
  wide against a spade's 772. Scale them uniformly and clubs break the
  9 and 10 layouts.
- **Noir has two edges, and both are load-bearing.** A dark card on a
  dark table has no silhouette of its own; at the 20%-of-height overlap
  a Klondike column uses, the inner white hairline is the only thing
  separating one card from the next. The outer dark hairline does the
  opposite job: a white-alpha rim can only ever be lighter than what it
  sits on, so on the one light-green table this site ships it did
  nothing at all. Thin either and something turns into a single mass.
- **Courts are split-mirrored** — emblem and pip in the top half, the
  same rotated 180° below — so the card reads from either end. King is a
  spiky crown with deep valleys, queen a scallop-and-pearl coronet on a
  tall band, jack a swallow-tailed banner: they have to be tellable apart
  by silhouette
  alone at a 60px card width. The bar used here is that any two courts
  differ at least as much as two *suits* do — measured as soft-IoU
  between the marks alone, rasterised at true card scale so area is
  normalised and only silhouette counts. Measured: the most-alike court
  pair is queen/king at 0.720–0.722, against a most-alike suit pair
  (spades/diamonds) of 0.768–0.777. Lower is more distinct, so the
  courts clear the bar, but queen/king is the deck's narrowest margin
  and any change to either mark should be re-measured. Note the
  confound: soft-IoU is bounded above by the two marks' area ratio, and
  the king carries less ink than the queen, so part of that margin is
  mass rather than shape. Normalising the king to the queen's ink and
  re-measuring still clears the bar, which is why the conclusion stands
  — but the raw number flatters it.
  An earlier version of this bar used mean |Δgrey| over whole rendered
  cards. That is the wrong instrument: courts share ~80% of their ink
  (panel, frame, pips, indices) while a suit change repaints every mark
  on the card, so the two quantities are not comparable — and on Noir,
  where hearts and diamonds share one ink, the "suit signal" floor is
  0.48, which anything clears.
- **Corner indices are outlines, not text.** Deliberate — an SVG that
  renders its numerals through a font stack renders *different numerals*
  on a machine without that font.
