Split portraits by set, and automate Series Two card production - #6
Merged
Conversation
Series One art was sitting flat in assets/portraits/, which leaves nowhere for the Hacking Legends (Series Two) portraits to land without colliding on card_NNN.png numbering. - Move all 50 approved Series One portraits to assets/portraits/legends/. - Add assets/portraits/hacking-legends/ for the Series Two art. - Point the generator's portraitDir at legends/ and update the portrait_asset paths in data/roster.locked.json (plus the generated dist/roster.json). - Document the per-set layout and naming convention in assets/portraits/README.md. Pure move: no portrait bytes changed. `open-source-legends.mjs validate` passes, and fails with the expected "missing approved portrait asset assets/portraits/legends/card_001.png" when the directory is removed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ThreatCrush Security Scan1 finding(s) MEDIUM: 1
Snippets are redacted; ThreatCrush never prints matched credential material. |
Series One was assembled by hand across four scripts and a manual copy into
public/cards/. This does the same job for Hacking Legends as one resumable
command chain, driven straight off src/data/hacking.ts.
pnpm hacking all [numbers...]
portraits gpt-image-2 portrait art -> assets/portraits-art/hacking-legends/
render HTML template -> dist/hacking/html/ (700x1043 @2x, free)
enhance image-to-image premium finish -> dist/hacking/enhanced/
publish -> public/cards/hacking/ at 500x745, matching Series One
Every stage skips existing output, so a failed batch is just re-run, and an
approved portrait in assets/portraits/hacking-legends/ always beats generated
art. The provider is picked from whichever API key is present (OpenAI
gpt-image-2 or Gemini), both overridable by env.
Also here:
- Series Two skill stack. The set had a single `impact` score and no sub-stats;
Series One's code/community axes do not describe hackers. Adds technical,
social, notoriety and influence to all 30 entries. Editorial ratings, flagged
as such in the type — not sourced facts.
- scripts/hacking-template.mjs: same bones as Series One so the decks read as
one product line, with an alias line, domains panel and a crest watermark
that keeps the finish pass from inventing something different on every back.
- publish writes front/back into hacking.ts, so the roster page and its
"artwork rendered" counter update themselves. RosterCard shows real art when
a card has it and the data-only proof when it does not.
- sharp becomes a real dependency. Three scripts already imported it while
telling you to install it by hand; publish needs it to resize, without which
a face ships at 3MB instead of 230KB.
Sample run of cards 1, 5 and 12 included. Verified: both series validate,
tsc and next build clean, /hacking-legends renders with no broken images.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two commits. The first makes room for the Hacking Legends art; the second generates it.
1. Split
assets/portraitsinto per-set directoriesSeries One art was flat in
assets/portraits/, so Series Two had nowhere to land without colliding oncard_NNN.pngnumbering.assets/portraits/legends/data/roster.locked.jsonassets/portraits/hacking-legends/src/data/hacking.tsNumbering is per-set, so
legends/card_001.png(Stallman) andhacking-legends/card_001.png(Mitnick) are both valid and unrelated. All 50 Series One portraits moved viagit mvwith no byte changes; the generator config,data/roster.locked.jsonand the generateddist/roster.jsonwere repointed. Repo-wide grep for the old path returns zero hits.2. Automate Series Two production
Series One was assembled by hand across four scripts plus a manual copy into
public/cards/.scripts/hacking-legends.mjsdoes the same job as one resumable chain, driven straight offsrc/data/hacking.ts(imported directly — Node strips the types, so there is no second copy of the roster).portraitsassets/portraits-art/hacking-legends/renderdist/hacking/html/(700x1043 @2x + source HTML)enhancedist/hacking/enhanced/publishpublic/cards/hacking/at 500x745Every stage skips existing output, so a failed batch is just re-run. An approved portrait in
assets/portraits/hacking-legends/always beats generated art and is never regenerated. Provider is chosen from whichever key is present — OpenAIgpt-image-2(the current latest, up from Series One'sgpt-image-1) or Gemini — and both model ids are env-overridable.Card design
scripts/hacking-template.mjskeeps Series One's bones so the decks read as one product line, and differs only where the data does: an alias line, a DOMAINS panel instead of signature projects, and an explicitrarityrather than one derived from impact.The set had a single
impactscore and no sub-stats, and Series One's code/community axes do not describe hackers. This adds technical / social / notoriety / influence to all 30 entries, rendered as the skill stack. They are editorial ratings, flagged as such in the type — the same kind of judgement Series One's ratings are, not sourced facts. Worth a review pass; they are easy to argue with.One non-obvious fix: the finish pass fills empty space by inventing, and it invented something different on every back (a vignette on one card, a full portrait on another). Claiming that space with a crest watermark and the alias makes the backs uniform across the deck.
Site wiring
publishwritesfront/backintohacking.ts, so the roster page and its "artwork rendered" counter update themselves.RosterCardshows real art when a card has it and the existing data-only proof when it does not; the pending placeholder now matches the card aspect ratio so the grid stays even mid-series.sharpNow a real dependency. Three scripts already imported it while the file headers told you to
npm installit by hand, soopen-source-legends.mjscould not run from a clean checkout.publishneeds it to resize — without that a face ships at 3MB against Series One's ~230KB.Verification
open-source-legends.mjs validatepasses, and fails with the expected missing-portrait error whenlegends/is moved aside.hacking-legends.mjs validatepasses: 30 on the roster, no structural errors.tsc --noEmitandnext buildboth clean./hacking-legendsrendered in a real browser: no broken images, counter reads 3/30.Not in this PR
pnpm hacking allwhen the stat lines and the three sample cards look right.dist/hacking/is gitignored, so the full-resolution faces are local only. Archive them before wiping if you want print masters.assets/portraits-art/is still flat and shared between the decks. Series Two writes to a subdirectory; Series One'sgen-portraits.mjsandrender-cards.mjsstill write to the root and would want the same treatment.public/cards/is still flat and Series One only. Splitting it would change live image URLs insrc/data/cards.ts, so it is a separate decision.🤖 Generated with Claude Code