Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ dist/html/
assets/portraits-art/

dist/enhanced/

# Hacking Legends (Series Two) working dirs. The published faces under
# public/cards/hacking/ are the committed record; these are intermediates.
# node scripts/hacking-legends.mjs all
dist/hacking/
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,49 @@ npm run db:migrate # applies db/schema.sql
Set the same two vars in the Railway service. `POST /api/waitlist` inserts email
signups into the `waitlist` table.

## Card production

Two decks, one per series. Approved portrait art lives under
`assets/portraits/<set>/` — see [assets/portraits/README.md](assets/portraits/README.md).

**Series One — Open Source Legends** (`data/roster.locked.json`, complete):

```bash
node scripts/open-source-legends.mjs validate # roster + portraits + template dims
node scripts/open-source-legends.mjs all # PNGs, per-card PDFs, batches, proofs
```

**Series Two — Hacking Legends** (`src/data/hacking.ts`, in progress):

```bash
pnpm hacking validate # roster checks, reports what art is missing
pnpm hacking all # portraits -> render -> enhance -> publish
pnpm hacking all 1 5 12 # ...only these card numbers
pnpm hacking render # re-render faces from the template, no API calls
```

The Series Two stages are:

| Stage | Output | Cost |
| --- | --- | --- |
| `portraits` | `assets/portraits-art/hacking-legends/` | one image call per card |
| `render` | `dist/hacking/html/` (700x1043 @2x + the source HTML) | free |
| `enhance` | `dist/hacking/enhanced/` — premium finish, text preserved | two image calls per card |
| `publish` | `public/cards/hacking/` at 500x745, and writes `front`/`back` into `src/data/hacking.ts` | free |

Every stage skips work that already exists, so a failed batch is just re-run.
Move a portrait from `assets/portraits-art/hacking-legends/` to
`assets/portraits/hacking-legends/` to approve it — the approved copy wins and is
never regenerated.

Set `OPENAI_API_KEY` (uses `gpt-image-2`) or `GEMINI_API_KEY` (uses
`gemini-3-pro-image-preview`); override with `IMAGE_PROVIDER`,
`OPENAI_IMAGE_MODEL` or `GEMINI_IMAGE_MODEL`. Rendering needs Chrome or
Chromium — set `CHROME_PATH` if it is not on the usual paths.

`dist/hacking/` is gitignored, so the full-resolution faces are local only.
Archive them before wiping the directory if you want print masters.

## Project layout

```
Expand Down
34 changes: 34 additions & 0 deletions assets/portraits/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Portraits

Approved, human-reviewed portrait art. One directory per card set.

| Directory | Set | Roster source | Status |
| ------------------ | -------------------------------- | ---------------------- | ---------------------------- |
| `legends/` | Open Source Legends (Series One) | `data/roster.locked.json` | Complete, 50 portraits |
| `hacking-legends/` | Hacking Legends (Series Two) | `src/data/hacking.ts` | In progress, 30 on roster |

## Naming

`card_###.png`, zero-padded to three digits, numbered within the set. The number
is the card's position in its own roster, so `legends/card_001.png` (Richard
Stallman) and `hacking-legends/card_001.png` (Kevin Mitnick) are both valid and
unrelated.

## Rules

- Only manually reviewed and approved art belongs here. Raw model output is
cached in `assets/portraits-art/`, which is gitignored.
- Portrait art only. No text, labels, logos, badges, borders, or watermarks —
the generator draws all of that.
- `node scripts/open-source-legends.mjs validate` fails if any Series One card
has no portrait in `legends/`.

## Prompts and generation

Series One: `node scripts/open-source-legends.mjs prompts` writes per-card
portrait prompts to `dist/portrait_prompts.md`.

Series Two: `pnpm hacking portraits` generates art into
`assets/portraits-art/hacking-legends/` (gitignored). Copy one into
`hacking-legends/` here to approve it — approved art always wins and is never
regenerated. See the card production section in the root README.
File renamed without changes.
Empty file.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
Loading
Loading