Files
2026-08-11 09:53:42 -04:00

252 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Side Cards
Original playing-card artwork for The Grind, generated locally with Draw Things
and assembled into dependency-free game assets.
## Current workflow
This project deliberately uses a simple hybrid format:
- J/Q/K illustrations are matching PNG artwork generated by Draw Things.
- A-10, indices and suit marks are deterministic SVG geometry.
- Each finished court card is a standalone SVG with its PNG illustration
embedded inside it. It scales normally in the game without hand-tracing the
figure.
Generate the nine non-Heart courts, then assemble the full deck:
```sh
./tools/.venv/bin/python tools/render_court.py --remaining
./tools/.venv/bin/python tools/build_deck.py
./tools/.venv/bin/python tools/audit_deck.py
```
Open `gallery.html` to inspect all 52 cards and the card back. The temporary game at
`../index.html` also uses these local exports; it no longer fetches Wikimedia
assets.
## Folders
- `concepts/` — calibration sheet and approved Hearts studies
- `art/courts/raw/` — locally generated court illustrations
- `exports/cards/` — finished standalone SVG cards and card back
- `exports/art/` — cleaned raster artwork embedded by the SVG exports
- `assets/fonts/` — Roboto Slab source font and its Apache-2.0 license
- `masters/` — an archived vector-figure experiment; not the deck pipeline
## Final deck files
The authoritative finished deck is the **53 standalone SVG files in
`exports/cards/`**: 52 faces plus `back.svg`. Each file is self-contained; the
court and back raster artwork is embedded as a data URI. `exports/manifest.json`
is the machine-readable file list, and `gallery.html` is only the visual review
page. Files in `exports/art/`, `concepts/`, `art/courts/raw/`, and `masters/`
are sources or build intermediates, not files to ship as the deck.
Run `tools/build_deck.py` once after any design change. It deterministically
rebuilds all 53 final SVGs together, including removal of detached court-art
pixel islands. A printer-specific PDF or raster package still requires the
printer's requested size, bleed, colour profile, and resolution.
The generated court figures are final game artwork. Roboto Slab rank
indices are converted to vector paths; suit marks,
number-card layouts and assembly remain deterministic.
House style specification: [`masters/STYLE.md`](masters/STYLE.md).
Third-party notices for the vendored protocol files and the model checkpoint:
[`tools/proto/LICENSE-NOTICE.md`](tools/proto/LICENSE-NOTICE.md).
The provenance sidecars and license notice are quiet background records; they
are not part of the day-to-day art workflow.
## Calibration v1
`concepts/calibration-v1.png`
- SHA-256: `ff8a176c188c647532cd57df5c953f78af44e33c90ca2a536470b52dc02e780f`
- Generator: OpenAI built-in image generation
- Reference images supplied to generator: none
- Status: concept only, not a production asset
### Prompt
> Design a cohesive original Anglo-American-style playing card system with the
> clarity and familiarity of a premium traditional casino deck, but with
> entirely new court characters, poses, faces, garments, ornament, linework,
> suit symbols, and card back. Show the Jack, Queen, and King of Hearts; Ace and
> Ten of Spades; one Joker; and two alternate card backs. Use crisp flat
> vector-like illustration, precise black keylines, a restrained red, black,
> golden-yellow, and muted-blue palette, white card stock, mirrored court
> composition, and conventional corner indices. No trademarks, logos, brand
> names, recognizable branded artwork, photorealism, or watermarks.
### Evaluation
- Court figures form a coherent family and remain legible at reduced size.
- Both back concepts are usable directions; the navy back has stronger contrast.
- The ten has the correct number of central pips.
- Several rotated indices are malformed. Production indices must therefore be
vector typography, never baked into generated artwork.
- Court detail should be reduced slightly before final vector reconstruction.
## DrawThings court study v1
`concepts/dt-court-qh-v1.png`
- SHA-256: `e53fd536a35f45f97c431a76e2a61af39262faf5bfecd56cc2ebf0aaab7cb073`
- Generator: local Draw Things server, `qwen_image_2512_bf16_i8x.ckpt`
- Settings: 640x896, 30 steps, DPMPP2MTrailing, guidance 4.0, seed 7
- Reference images supplied to generator: none
- Status: concept only, not a production asset
Generated locally via `tools/dt_client.py` — no metered image API. This exists to
confirm the house style is reachable without OpenAI image generation.
### Evaluation
- Palette, keyline weight, and flat vector-like rendering match the calibration
sheet's direction closely enough to serve as the ongoing concept source.
- Mirrored two-way court composition resolved correctly.
- Carries no indices or text by design, which suits the production rule above:
suit symbols and indices are vector work, never generated.
- Cost is wall-clock, not money: ~7 minutes per 640x896 card at 30 steps.
## DrawThings court study v2 (img2img)
`concepts/dt-court-qh-v2.png`
- SHA-256: `455436aca85380a9f5e2a0c4fe5b1577249aa5d7835e1c01ea205825f680072e`
- Generator: local Draw Things server, `qwen_image_2512_bf16_i8x.ckpt`
- Settings: 640x896, 30 steps, DPMPP2MTrailing, guidance 4.0, seed 88,
img2img strength 0.68
- Reference image: the Queen of Hearts crop from `calibration-v1.png`, with the
two corner index strips painted white before encoding
- Model SHA-256: `b60a1430040108f8808ef20b47196b09526b1394f7438feeba5538bb89248354`
- Draw Things: `1.20260716.0`
- Status: concept only, not a production asset
v2 predates the provenance sidecars, so its prompts are recorded here in full.
> Original playing card court figure illustration, a queen wearing an ornate
> golden crown, crisp flat vector-like illustration, precise black keylines,
> restrained palette of red, black, golden-yellow and muted blue on white card
> stock, mirrored two-way composition, ornate patterned robes, holding a
> stylized flower, thin black double-line border frame, completely empty plain
> white corners, plain white background
Negative prompt:
> corner index, corner marking, letter Q, rank letter, suit index, heart symbol
> in corner, pip, text, letters, numbers, typography, watermark, signature,
> logo, photorealistic, photograph, 3d render, soft gradient shading, blurry,
> noisy, drop shadow, heavy solid black
### How this was reached
Four rounds of text-only prompting locked the style but oscillated on layout:
each composition fix over-corrected the previous one.
- Asking for a "premium traditional casino deck" reintroduced corner indices.
- "Generous white margin" shrank the figure until it floated in white.
- "Classic diamond lozenge silhouette" was drawn as a literal rhombus outline.
- "Robes flare to the card edges" pushed the robes outside the border frame.
Pinning the composition with img2img off the mockup solved this in one pass.
Style, palette, and keyline weight were already matched by round 2.
### Evaluation
- Composition, palette, and figure now track `calibration-v1.png` closely, with
cleaner and more consistent linework than the original sheet.
- Strength 0.55-0.72 preserves composition; 0.85 drifts and garbles the index.
- **Open issue:** the model re-draws a corner suit pip even when the reference
corners are blanked and pips are negative-prompted — it infers them from the
card context. In this render the pip lands *inside* the border frame, so it
cannot be removed by cropping to the panel. Removing it needs inpainting or a
mask, or the vector stage must cover that region.
## Court family test v3 (J/Q/K of Hearts)
`concepts/dt-court-jh-v3.png`, `dt-court-qh-v3.png`, `dt-court-kh-v3.png`
Each PNG has a JSON sidecar recording both prompts, the checkpoint SHA-256, the
Draw Things build, the reference hash, all sampler settings and the client
revision. Regenerate with `tools/render_court.py JH QH KH`.
- Model: `qwen_image_2512_bf16_i8x.ckpt`
SHA-256 `b60a1430040108f8808ef20b47196b09526b1394f7438feeba5538bb89248354`
- Draw Things: `1.20260716.0`
- Settings: 640x896, 30 steps, DPMPP2MTrailing, guidance 4.0, seed 88,
img2img strength 0.68, seed_mode ScaleAlike
- Reference: each card's cell from `calibration-v1.png` (cells measured by
background-gutter detection: all four are 329x460, ratio 0.715), resized to
640x896 with the two corner index strips painted white
- Status: approved Heart court artwork used by `tools/build_deck.py`
### Evaluation
- The three cards read as a coherent family: consistent linework, palette,
keyline weight and mirrored composition. The King's beard, crown and sword
resolved without trouble.
- Rank letters are absent, as intended; `build_deck.py` adds them reliably.
- The generated Heart marks are correct and align with the SVG suit overlay.
- Generated frame segments are locally inpainted out during assembly. One
continuous SVG inner frame is then drawn behind the figure, giving the court
the intentional traditional frame-break effect. The approved upper figure supplies both ends of the card by exact
180-degree rotation; a symmetric blended join avoids mismatched lower art.
- The temporary game has been verified at 110×154. No smallest production size
has been chosen, so this does not constrain the master artwork.
The house style specification derived from this test lives in
[`masters/STYLE.md`](masters/STYLE.md).
## Archived vector experiment — Queen of Hearts
`masters/queen-hearts.svg`
This was an experiment in hand-authoring the generated figure as SVG. It is not
used by `build_deck.py`; the practical deck keeps court illustrations as raster
art inside standalone SVG cards.
Editable groups: `frame`, `indices`, `veil`, `garments`, `ornament`, `props`,
`hair-back`, `face`, `hair-front`, `crown`, `keylines`. All colour lives in one
stylesheet block at the top; the rank glyph is drawn geometrically so it needs
no font at render time.
**Status: structurally correct, artistically unfinished.** The mirror, clip,
frame, indices, seam, palette and group organisation are all verified working.
The figure drawing is a schematic — the face is doll-like, the hair reads as
flat slabs, the robe silhouette is a lens rather than cloth, and the ornament is
far sparser than the concepts. It is a sound skeleton to refine, not a finished
master.
### Size behaviour
`tools/size_test.py ../masters/queen-hearts.svg` at 110/220/440/1050:
| 110px | 220px | 440px | 1050px |
|---|---|---|---|
| 0.189 | 0.119 | 0.053 | 0.022 |
It reads cleanly at all four sizes, so a single universal master works — but
only because the art is currently sparse. **Re-run this once real detail is
added**, since that is when the small-size question actually bites.
## Generation toolchain
`tools/` holds a local Draw Things gRPC client. Run `tools/setup.sh` once, then
drive it through `tools/dt_client.py`.
Notes that are not obvious from the Draw Things docs and cost real time to work
out — see also the `proto/` copies vendored from `drawthingsai/draw-things-community`:
- The app's API server speaks **TLS** on port 7859 and serves only a self-signed
leaf (`CN=localhost`, issuer "Draw Things Root CA"). The client pins that leaf.
- `ImageGenerationRequest.configuration` is a **FlatBuffers** blob
(`proto/config.fbs`), not protobuf. Fields are written by slot index in
declaration order; deprecated fields still consume their slot.
- `start_width` / `start_height` are in units of **64px**, so 640x896 is 10x14.
- Returned images are **not** PNG. They are s4nnc tensors: a 68-byte ccv header
(`CCV_16F`, NHWC, dims) followed by an fpzip stream, with pixel values in
[-1, 1]. `dt_client.decode_png` handles this.