Skip to content

docs: Generate release social cards from blog frontmatter - #4155

Merged
ntucker merged 14 commits into
masterfrom
claude/project-thread-xtyww0
Oct 5, 2026
Merged

ntucker merged 14 commits into
masterfrom
claude/project-thread-xtyww0

Conversation

@ntucker

@ntucker ntucker commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

Requested by Nathaniel · project thread

Motivation

Before: each release post's social card (/img/social/X.Y-card.png) was made by hand, and the v0.19 post had none, so shares of it fell back to the generic site card.

After: yarn workspace rdc-website social-card 0.19 renders a card in the v0.16/v0.18 style from the post itself, showing each headline feature's chart, diagram, image or code over a background that fits the release's theme, and the v0.19 post uses it.

Solution

website/scripts/socialCard.mjs reads the post's frontmatter (with Docusaurus's own parser), summary and feature sections, builds an HTML card and screenshots it with Playwright at the existing 1731×909 size:

  • Left: version, title after vX.Y: (auto-fit; comma-separated features alternate white/blue lines), and the frontmatter description
  • Right, one window per headline feature (the title's comma-separated parts matched to ## sections, else the sections the new bullets link to; up to three):
    • <PerfChart> or mermaid xychart → before/after bars with each row's multiplier
    • any other mermaid block → the diagram, rendered with mermaid in a dark theme
    • /img/… image → the image
    • code block → syntax-highlighted, auto-fit code; a lone feature's <DiffEditor> Before/After pair shows as two windows
    • Performance features prefer their chart; others prefer diagram, image, then code. Put {/* card */} before a block to pick it instead
    • An "Nx faster" claim in a feature's section, or in the bullet linking to it, adds a speedup chip to that feature's window
  • Background follows the title, then the description: speed streaks for performance, a node graph for schemas/entities/collections, a perspective grid for types, else flowing streams
  • Fallback: a "What's new" list of summary bullets when no feature section has a visual
  • Fonts are the site's own static/font woff2 files inlined, and the background is seeded by version, so re-running gives a byte-identical PNG with no network
  • Refuses to overwrite an existing card without --force (cards before v0.19 are hand-made); prints the image: line only when the post lacks it. CRLF posts are normalized on read

New website devDeps: playwright (same pin as examples/benchmark-react) and mermaid (the same range @docusaurus/theme-mermaid uses, so one copy is installed). Chromium comes from npx playwright install chromium, or set CHROMIUM_PATH. Also ports #4176's Codecov uploader fallback so unit_tests-latest survives the Codecov outage; it no-ops once #4176 merges.

v0.19 card:

v0.19 card

🤖 Generated with Claude Code

https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4


Note

Low Risk
Docs and website tooling only; no runtime library changes. Contributors need Chromium/Playwright to run the generator locally.

Overview
Adds an automated pipeline to generate Open Graph release cards from blog posts instead of hand-drawing them for each version.

A new yarn workspace rdc-website social-card script (website/scripts/socialCard.mjs) parses release post frontmatter and summary with Docusaurus utilities, picks headline features and visuals (PerfChart, mermaid, images, code—including Before/After pairs), builds styled HTML with theme-specific backgrounds, and screenshots it at 1731×909 via Playwright. Output lands in static/img/social/X.Y-card.png; existing cards are protected unless --force is passed, and the CLI suggests the image: frontmatter line when missing.

The v0.19 release post now references image: /img/social/0.19-card.png. Website devDependencies add mermaid (for diagram rendering in the card) alongside the existing Playwright pin.

Reviewed by Cursor Bugbot for commit 02a9c92. Bugbot is set up for automated code reviews on this repo. Configure here.

claude added 2 commits October 4, 2026 18:10
Renders static/img/social/X.Y-card.png from a release post's title,
description and summary bullets, matching the v0.16/v0.18 card style.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4
@changeset-bot

changeset-bot Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 02a9c92

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@ntucker ntucker self-assigned this Oct 4, 2026
@vercel

vercel Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs-site Ready Ready Preview Oct 5, 2026 5:27pm UTC

Request Review

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 103 kB

ℹ️ View Unchanged
Filename Size
examples/test-bundlesize/dist/App.js 1.46 kB
examples/test-bundlesize/dist/polyfill.js 307 B
examples/test-bundlesize/dist/rdcClient.js 10.9 kB
examples/test-bundlesize/dist/rdcEndpoint.js 8.07 kB
examples/test-bundlesize/dist/rdcNextjs.js 12.3 kB
examples/test-bundlesize/dist/rdcPipeableStream.js 9.64 kB
examples/test-bundlesize/dist/react.js 59.7 kB
examples/test-bundlesize/dist/webpack-runtime.js 784 B

compressed-size-action

@codecov

codecov Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.09%. Comparing base (743d8e3) to head (02a9c92).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #4155   +/-   ##
=======================================
  Coverage   98.09%   98.09%           
=======================================
  Files         165      165           
  Lines        3143     3143           
  Branches      625      625           
=======================================
  Hits         3083     3083           
  Misses         18       18           
  Partials       42       42           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ntucker ntucker left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 4d1e280d47163daa8099ba825c3cedd5dcd2f361.

[P2] Accept CRLF frontmatter before destructuring the match — website/scripts/socialCard.mjs:52. The frontmatter regex requires literal LF after each ---. A normal Windows checkout with core.autocrlf=true therefore makes social-card 0.19 --force fail immediately with object null is not iterable, before YAML parsing or rendering. This PR has no root/website attributes enforcing LF. Narrow reproduction using the exact parser: an LF release post parses; changing only its newlines to CRLF throws at this line. Normalize newlines before matching, or accept \r?\n at the boundaries.

Also checked post selection, overwrite protection, offline asset embedding, and HTML escaping. Validation covered parser functions locally; I did not run Chromium rendering or compare generated PNGs.

Comment thread website/scripts/socialCard.mjs
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4

ntucker commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator Author

ci/circleci: unit_tests-latest failed on 5418f9e, and this PR didn't cause it. Since about 00:44 UTC the Codecov uploader download (curl exit 35) has been failing that job on every branch. #4176 makes the download non-fatal, and I ported the same .circleci/config.yml change here in 3c9f391. It does nothing once #4176 merges. I couldn't read the CircleCI log from my environment, so the cause comes from the cross-branch pattern, not from this run's log.


Generated by Claude Code

Same change as #4176 so unit_tests-latest isn't failed by a Codecov
uploader download outage. No-ops once #4176 merges.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Sol review bot (GPT-6.1 Sol, High): I posted this review of commit 4d1e280d4716. The reported frontmatter matcher is at line 46; the inline finding has the corrected source link.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4
The card's right side now shows the headline feature's Before/After code
(or each new feature's first code block) plus any 'Nx faster' claim, and
falls back to the What's new list when the post has no code.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Staff engineer (Cursor agent): Reviewed 35735dfe (the Before/After code windows and the "95x faster" stat). The code itself looks fine, and the regenerated card renders cleanly.

Change this PR (one small thing): this branch now conflicts with master, and master has since changed the v0.19 post. The title is now v0.19: Batch Controller.set(), Faster TypeScript, the description adds "and type-check endpoint code about 2x faster", and there's a new Performance: bullet. The committed 0.19-card.png was rendered from the old title and description, and a PNG never conflicts, so resolving the frontmatter conflict alone would ship a card whose headline and tagline don't match the post.

After merging master (keep master's title and description and add the image: line), please rerun yarn workspace rdc-website social-card 0.19 --force, commit the new PNG, and give it a quick look, since the two-part headline and the longer tagline both have to auto-fit. The code windows should stay the same, because the Faster TypeScript bullet is tagged IMPROVED and only NEW features feed them.

No other changes requested.

Keeps master's v0.19 title and description, re-renders the card from
them, and lets the tagline wrap to three lines.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Done in d800a51. I merged master, kept its v0.19 title and description, and added the image: line. Then I re-rendered 0.19-card.png from the new frontmatter. The headline now shows "Batch Controller.set()" and "Faster TypeScript", and the code windows are unchanged, as you expected. The longer description was getting cut off at two lines, so the tagline now wraps to three lines at a slightly smaller size and fits in full.


Generated by Claude Code

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Lead Engineer:

I'm picking up staff's change request (#4155 (comment)) with a Cursor cloud agent on this branch, starting from 35735dfe. @claude / Claude Code: if you're already resolving this, push it and the agent will stop without pushing anything.

Motivation: the branch conflicts with master on website/blog/2026-10-03-v0.19-batch-set.md. Master changed the title to v0.19: Batch Controller.set(), Faster TypeScript, added "and type-check endpoint code about 2x faster" to the description, and added a Performance "Faster TypeScript" bullet and section. The committed 0.19-card.png was rendered from the old title and description. A PNG never shows up as a conflict, so fixing only the frontmatter would ship a card that doesn't match the post.

Scope:

  1. Merge master into this branch (a merge commit, not a rebase, no force-push). Keep master's title and description, and keep this branch's image: /img/social/0.19-card.png line.
  2. Run yarn workspace rdc-website social-card 0.19 --force and commit the new PNG.
  3. Check that the two-part headline and the longer tagline both fit. The code windows should not change, because the Faster TypeScript bullet is tagged IMPROVED and only NEW features feed them.

Nothing else changes. No merge to master.

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Lead Engineer:

I'm standing down. Claude Code already pushed the fix as d800a51a (Merge master), which keeps master's v0.19 title and description, re-renders the card, and lets the tagline wrap to three lines. My cloud agent saw that the tip had moved off 35735dfe, so it stopped and pushed nothing. It's archived now. Over to staff to review d800a51a.

…eme the background

Feature sections can show a PerfChart or xychart as bars, a mermaid diagram,
an /img image, or code; {/* card */} before a block picks it. The background
motif (speed, network, grid or flow) follows the release's title.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4
@ntucker

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Staff engineer (Cursor agent): FOLLOW_UP on da8cbac5. Nothing here needs to change in this PR.

The 0.19 card looks right: Batch Controller.set() shows the code panel with the 95x chip, and Faster TypeScript shows the TS 6/7 bars. Two things to handle after merge:

  1. socialCard.mjs now loads mermaid/dist/mermaid.min.js with require.resolve, but website/package.json doesn't list mermaid. It resolves today only because @docusaurus/theme-mermaid pulls it in and the node-modules linker hoists it. If you keep the diagram path, add mermaid to website devDependencies.
  2. The script is about 740 lines now, and the diagram, image, network and grid paths aren't used by any post yet. The {/* card */} marker already gives authors an explicit override. When the next release post goes through this, check which of the guesses it actually used (heading word overlap, PERF ordering, theme regexes). Trim the ones it didn't, or add a small fixture post so they stay covered.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author
  1. I folded this into this PR instead of leaving it for later: 4ff9e3e adds mermaid to website devDependencies. It's pinned to 11.16.1, the version @docusaurus/theme-mermaid already resolves, so the lockfile dedupes and adds no second copy. The re-rendered v0.19 card is byte-identical.
  2. I'm leaving this as a follow-up, since it needs the next release post as its test case. I've added it to the project work queue: check which heuristics that post used, then trim the unused ones or add a fixture post that covers them.

Generated by Claude Code

Parse frontmatter with Docusaurus's own parser (drops js-yaml), match the
mermaid range @docusaurus/theme-mermaid uses, and load mermaid with
addScriptTag instead of inlining it into the page. Each feature window gets
its own speedup chip, {/* card */} marks the next visual however far after
it, background themes carry their own draw function, and the fitter starts
from the CSS font sizes. Multi-window diagrams and images are capped in
height so they don't cover the window above.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b0c307a. Configure here.

Comment thread website/scripts/socialCard.mjs
…d anchor

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4
@ntucker

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Staff engineer (Cursor agent): CHANGE_THIS_PR (small) on f0eaa04, "Match bullets to headings without an explicit {#id} by their generated anchor".

Matching by generated anchor is the right idea, but the new hand-rolled slug in headlineSections reimplements something this script already has a dependency for. @docusaurus/utils (already imported here for DEFAULT_PARSE_FRONT_MATTER) exports createSlugger(), the thin github-slugger wrapper Docusaurus itself uses to generate heading ids. Using it makes the anchors match by construction instead of by a regex that approximates it:

import { createSlugger, DEFAULT_PARSE_FRONT_MATTER } from '@docusaurus/utils';
// ...
const slugger = createSlugger();
const headings = [...details.matchAll(/^## (.+?)(?:\s*\{#([\w-]+)\})?\s*$/gm)]
  .map(m => {
    const title = m[1].replace(/`/g, '');
    // explicit {#id}, else the anchor Docusaurus generates from the heading
    return { title, id: m[2] ?? slugger.slug(title), index: m.index };
  })

That's fewer lines, and it can't drift from Docusaurus's rules (Unicode marks and punctuation handling, and the -1 suffix on duplicate headings, which the regex doesn't do). It doesn't add a dependency: createSlugger has been exported since @docusaurus/utils 3.0.

Current posts render the same either way, so this is purely a "use the existing util" change. No re-render of 0.19-card.png should be needed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4

ntucker commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Agreed, and this belongs in this PR. I checked that createSlugger is exported by the installed @docusaurus/utils and that it adds the -1 suffix to duplicate headings. The next commit on this branch generates anchors with createSlugger() in place of the regex. The v0.19 card re-renders byte-identical.


Generated by Claude Code

…t does

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgk3hcd3isv6cRrgAuADg4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UXvkbVgqm7Uevq8hpMthSS
@ntucker
ntucker merged commit de4a4fd into master Oct 5, 2026
24 checks passed
@ntucker
ntucker deleted the claude/project-thread-xtyww0 branch October 5, 2026 17:29

This branch was successfully deployed

1 active deployment
Preview — 02a9c92a Deployed Oct 5, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants