Per-card shareable pages with card-art link previews, plus consistency fixes - #9
Merged
Merged
Conversation
Every card now has its own page — /cards/<slug> for Series One and /hacking-legends/<slug> for Series Two — so a legend can be shared as a link instead of a screenshot. Sharing: - Each page generates a 1200x630 opengraph-image at build time with the card art on the left and the stat line on the right. The card faces are 500x745 portrait, which X and LinkedIn refuse to render large, so a landscape composite is what actually shows the card in a preview. - All 77 OG images are prerendered by generateStaticParams; no runtime image work. SEO: - Canonical URLs on every page, Person JSON-LD on card pages, and sitemap.xml covering all 82 URLs plus robots.txt. - The card grids now link to the detail pages, so all 47 Series One permalinks are crawlable from /cards. Consistency, all now derived from the data rather than hardcoded: - Homepage said both 47 and 50 legends. The stat strip read "50"; it now reads cards.length, and gained the Series Two roster count. - Collector's Box advertised "All 16 cards" -> All 47 cards. - Homepage said Hacking Legends had no artwork while its own page showed 30/30 rendered. It now reports illustrated and locked counts from the roster. The "what ships next" list no longer promises illustration that already happened. Sourcing: - Hacker gains a required `sources` field, populated for all 30 entries. Every URL was fetched and returned 200 before being written in. - Sources render on the card page and in the expanded roster report, so the historical claims can be checked. RosterCard is an <article> rather than a <button> now, because those links cannot live inside a button. Contribution guide: - It pointed at src/data/legends.ts, which does not exist, and showed a card shape with signatureProjects/skills that no longer matches either series. It now documents the real pipeline: src/data/hacking.ts as the Series Two source of truth, data/roster.locked.json for Series One with src/data/cards.ts generated from it, and the render step that writes the front/back fields. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| <> | ||
| <script | ||
| type="application/ld+json" | ||
| dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} |
| <> | ||
| <script | ||
| type="application/ld+json" | ||
| dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} |
ThreatCrush Security Scan3 finding(s) MEDIUM: 3
Snippets are redacted; ThreatCrush never prints matched credential material. |
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.
Addresses the review feedback: shareable per-card pages first, then the consistency issues.
Per-card pages (the headline item)
Every card has its own page —
/cards/<slug>for Series One,/hacking-legends/<slug>for Series Two. Card faces, full scouting report, stat bars, projects/domains, prev/next, copy-link + share-on-X + download-the-art.Link previews use the card art. The card faces are 500×745 portrait, which X and LinkedIn refuse to render as a large image — they'd fall back to a small square crop. So each page builds a 1200×630 composite with the card on the left and the stat line on the right:
/cards/linus-torvalds/hacking-legends/kevin-mitnickAll 77 OG images are prerendered at build via
generateStaticParams— no runtime image work.SEO: canonical URLs,
PersonJSON-LD per card,sitemap.xml(82 URLs) androbots.txt. The grids now link to the detail pages, so all 47 Series One permalinks are crawlable from/cards.Consistency fixes
Every count is now derived from the data instead of hardcoded:
'50'; it now readscards.length, and gained the Series Two roster count.All 47 cards.Source links on Hacking Legends
Hackergains a requiredsourcesfield, populated for all 30 entries. Every URL was fetched and returned 200 before being written in. They render on the card page and in the expanded roster report.RosterCard's root changed from<button>to<article>— source links and the card permalink can't live inside a button. Expand/collapse moved to a button in the footer.Contribution guide
It pointed at
src/data/legends.ts(doesn't exist) and showed a card shape withsignatureProjects/skillsthat matches neither series. Now documents the real pipeline:src/data/hacking.tsas the Series Two source of truth,data/roster.locked.json→ generatedsrc/data/cards.tsfor Series One, and the render step that writes thefront/backfields.Not included
The "make your own contributor card from your GitHub handle" idea — deferred as suggested.
The image-to-image enhance pass has corrupted text on several shipped Series Two fronts. The prompt tells it not to touch text; it did anyway:
This undercuts exactly the credibility the source links are meant to add, so it's worth a decision. All 30 approved portraits are committed under
assets/portraits/hacking-legends/, sopnpm hacking rendercan regenerate text-accurate faces with no API calls — but that drops the premium finish on every card, which is an art-direction call rather than mine to make. Not touched in this PR.Separately,
buildBackrenders thenotefield inside quote marks, which reads as a quotation from the subject even thoughhacking.tsstates the field is editorial voice. Worth a look on the same pass.🤖 Generated with Claude Code