Blog Feature and Meta Image Updates - #17937
Conversation
Docs ReviewScope: All 63 changed files in PR 17937 -- blog feature/meta image system overhaul, Hugo layout templates, blog-meta-image skill updates, blog post frontmatter additions, documentation updates, and Stencil component type changes. Overall this is a well-structured PR that cleanly separates feature images (hero/listing) from meta images (OpenGraph/social). The two-pass rendering approach in the compose script is solid. Issues
Suggestions (non-blocking)
SummaryThe core architecture change (feature image + meta image separation) is clean and well-documented across the skill files, BLOGGING.md, CONTRIBUTING.md, and the blog archetype. The main concern is the intentional removal of listing images for posts without feature_image (item 1) and the unrelated components.d.ts changes (item 2). Mention me (@claude) if you would like additional reviews or want me to help fix any of the above. |
|
Your site preview for commit 1b83415 is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-1b83415d.s3-website.us-west-2.amazonaws.com. |
kimberleyamackenzie
left a comment
There was a problem hiding this comment.
Love this - if we decide to implement, it sounds like maybe we can cut Figma out of the process for day-to-day blog authors? If so will you loop me in? Because we pay for a bunch of seats in Figma for folks who only use it for blog meta images.
|
@kimberleyamackenzie Yep! Would just be me making the feature images in Figma if we do it. |
|
Your site preview for commit 2f47456 is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-2f474565.s3-website.us-west-2.amazonaws.com. |
|
@claude Re-review |
|
Claude finished @jeffmerrick's task in 2m 14s —— View job Re-review
SummaryAll 6 issues from the previous review have been addressed. The
One New Minor FindingArchetype is missing The This is non-blocking — the existing placeholder image is already in Everything Else Looks Good
This is ready to merge once you've confirmed the archetype note above. |
|
Your site preview for commit 4c340ce is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-4c340ce2.s3-website.us-west-2.amazonaws.com. |
|
Your site preview for commit bc9027a is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-bc9027a6.s3-website.us-west-2.amazonaws.com. |
|
Thanks @CamSoper! Just a note that I'm going to spend some time creating images for the first two pages or so before merging. |
|
Your site preview for commit 6a48fb3 is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-6a48fb39.s3-website.us-west-2.amazonaws.com. |
|
Your site preview for commit d97599d is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-d97599db.s3-website.us-west-2.amazonaws.com. |
|
Your site preview for commit 52d8416 is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-52d8416c.s3-website.us-west-2.amazonaws.com. |
cnunciato
left a comment
There was a problem hiding this comment.
Looks great! ✨ Noticed a few little things we may want to fix up before we merge, but leaving an approval here to keep you unblocked.
There was a problem hiding this comment.
I almost hesistate bring it up because it's so minor, but it's poking at my OCD, so I will 😄 To my eyes at least, the top circle looks ever so slightly off center.
There was a problem hiding this comment.
Thank you for bringing it up! That would've bugged me when I noticed it later. Fixed!
|
|
||
| ``` | ||
| header: "Logo Tint Style" | ||
| question: "How should the tint color be applied to the logos?" |
There was a problem hiding this comment.
This is likely the fault of the logos we're using, but I tried both options with a faked-up post involving AWS, TypeScript, and Docker, and neither one came out quite right:
Overlay:
Colorize:
As a follow-up (or before merge, if it wouldn't be too big a deal), we may want to run through these logos and check 'em all against our new darker backgrounds to make sure they look right. (Just wanted to call it out now to make sure it didn't get lost.)
There was a problem hiding this comment.
@cnunciato Thanks for catching this, the colorize wasn't working as expected.
I've made some updates so the overlay method should work with all the logos we currently have, since the skill can also download logos, it may not work with all future logos. I've also adjusted the colorize method to look slightly better, but it really depends on the logo (it's basically a backup in case overlay doesn't work). So results may not be always great on the 2x and 3x versions since different logos might work better with different methods.
Hopefully we will mostly be designing custom images so it won't come up too much.
Co-authored-by: Christian Nunciato <chris@nunciato.org>
|
Your site preview for commit f7bf295 is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-f7bf295e.s3-website.us-west-2.amazonaws.com. |
|
Your site preview for commit 93f0b89 is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-93f0b892.s3-website.us-west-2.amazonaws.com. |
|
Your site preview for commit 0737ad8 is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-0737ad8d.s3-website.us-west-2.amazonaws.com. |
Dark-filled logos (e.g., AWS) were nearly invisible in color tint mode because the original pixel lightness was preserved as-is. This remaps lightness into [0.45, 1.0] so dark pixels become visible while preserving relative contrast. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cnunciato
left a comment
There was a problem hiding this comment.
Looks great! I added a bit to the script to set a baseline lightness value to keep dark logos (e.g., the text in the AWS logo) from getting lost in the dark background.
Click the merge button when you're ready! 🙌🏻
|
|
||
| ``` | ||
| header: "Logo Tint Style" | ||
| question: "How should the tint color be applied to the logos?" |
|
Your site preview for commit c1c1669 is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-17937-c1c16697.s3-website.us-west-2.amazonaws.com. |
… feature image (#20060) * Add build-time blog social card (blog.mjs + generator wiring) New Satori "blog" template renders the 1200x628 OpenGraph card for a blog post at build time — the post's feature image bled off the right edge, faded into the dark violet field by a gradient scrim, with a "Blog" badge, the fitted title, and the Pulumi wordmark in the cleared left column. It reproduces the retired Python meta-image composite; posts with no feature_image fall back to a bundled generic art plate (blog-generic.png). Wires it into scripts/generate-meta-images.mjs as a new recursive "blog" SECTIONS entry (skips drafts; feature bytes fold into the cache key via featureHash). No OG_TEMPLATE_VERSION bump — new manifest keys only. The sampleGroupBy call site now also receives p.fields so blog can sample one card per kind (feature vs generic). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Blog layouts: route meta image through the shared partial; archived panel RSS <description> image and the BlogPosting JSON-LD image now resolve via partials/meta-image-url.html instead of reading .Params.meta_image directly, so a post with no meta_image picks up its build-time generated card (and both stay in sync with the OpenGraph tags). blog-entity.html keeps the blog-specific og-default fallback. single.html gains a collapsed "Archived feature image" panel keyed on the bundle's meta-legacy.* resource, so migrated off-brand legacy images stay viewable at the bottom of the post. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Rework blog-meta-image skill into blog-feature-image (feature-only) The skill no longer composites a meta.png; the OpenGraph card is now generated at build time (blog.mjs). Renamed .claude/commands/blog-meta-image -> blog-feature-image (invoked as /blog-feature-image; SKILL.md keeps a "formerly /blog-meta-image" note). - SKILL.md: drop the meta compositing step; frontmatter update sets only feature_image. - compose_meta_image.py: delete meta mode (feature/overlay/logo/text compose, draw_text, word-wrap, code-span extraction); keep the template + logo placement + tint pipeline. - catalog.yaml / asset-catalog.md: remove meta_canvas + text sections; delete the meta-overlay.png and meta-logo.png template assets. - archetypes/blog-post: drop meta.png and the meta_image field; feature_image comment now notes it drives the build-time social card. - new-blog-post.md: stop copying a meta placeholder; drop meta_image from the generated frontmatter; reword guidance to /blog-feature-image. - delete the now-unused blog-post-meta-placeholder.png. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Migrate blog Group A (feature_image posts) to build-time cards The 66 posts that already carry a feature_image drop their committed meta.png and the meta_image frontmatter, so partials/meta-image-url.html serves the new build-time blog card. 21 of them had their original committed meta image overwritten by #17937 — those are restored from the parent commit (306c185^) as meta-legacy.png first (special case: iam-for-postgres.png), surfaced in the post's collapsed "Archived feature image" panel. No Group A post referenced its meta.png in its body, so no post body changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Migrate blog Group B (legacy meta images) to build-time cards The remaining 700 posts drop meta_image so partials/meta-image-url.html serves the build-time card. 645 off-brand legacy meta images are renamed to meta-legacy.<ext> and surfaced in the post's collapsed "Archived feature image" panel; the 55 whose meta image is still referenced elsewhere keep the file untouched (14 referenced by data/blog_series.yml, 41 shown inline in the post body). No post body content is changed — every body-shown image is kept (the drift.png / set-up-drift.png filename collision is handled by exact delimiter matching). blog_series.yml needs no edit; all 15 entries still resolve. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Update references/tooling for the build-time blog card - schedule-posts.py: social media image prefers feature.png, falls back to legacy meta.png/meta.jpg. - AGENTS.md: add blog + events to the generator's meta-image list; drop the "blog is the exception" note; document feature_image-driven cards and the meta-legacy.png archive. - BLOGGING.md: front-matter example uses feature_image; images section and checklist drop meta_image (build-time card from title + feature image); add an archived-images note; point authors at /blog-feature-image. - docs-review/references/blog.md: the retired-logo / placeholder meta_image checks are now custom-override-only (the placeholder file is gone and posts ship no meta_image); meta-legacy.png is never flagged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Blog card: vertically center the badge + title group Give the left column a fixed height spanning the band between the top padding and the Pulumi wordmark, with justifyContent center, so the "Blog" badge + title sit centered as a group rather than top-anchored — balanced for short titles. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Blog card: narrow the title box to 640 so wide titles clear the artwork At 700px the title column reached x=790 and could overlap a wide feature image's artwork (e.g. the two-logo KubeCon card). 640px pulls the longest lines left of the artwork while barely affecting normal titles. * Add proper feature images to 10 blog series Each of these series has a new on-brand hero image (1884x1256). Every post in a series gets the same feature.png + feature_image front-matter, so the build-time generator now renders a branded feature card (instead of the generic plate) for all 38 posts. Their series entries in data/blog_series.yml are repointed at the new feature.png so the /blog/series/ listing matches. Series without a new image (neo-things, platform-engineering-pillars, pulumi-copilot, organizational-patterns, kubernetes-getting-started) are untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add feature images to the remaining 5 blog series The final 5 series (neo-things, platform-engineering-pillars, organizational-patterns, kubernetes-getting-started, pulumi-copilot) get their new on-brand hero image applied to every member post, matching the first batch. Membership is tag-based here (these series are collected via /blog/tag/<slug>/, and some have no `series:` front-matter key). 24 posts get feature.png + feature_image, and their blog_series.yml entries repoint at the new image. All 15 series now have proper feature images and branded build-time cards. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Fix neo-things series: add the missing series: key to both posts A blog series needs two things wired up: the series slug as a tag (so the post appears on /blog/tag/<slug>/, the series landing page linked from /blog/series/) AND a matching series: front-matter key (so single.html shows the "In This Series" sidebar, which finds siblings via where .Params.series). The two neo-things posts were only tagged, so they listed on the series page but showed no series-nav sidebar. Adding series: neo-things brings them in line with every other series. Audited all 15 series: this was the only mismatch, and there are no orphan series keys. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Lint: enforce blog series tag/key consistency Add a front-matter check to scripts/lint/lint-markdown.js that fails when a blog post is tagged with a defined series slug but missing the matching series: key (or vice versa) — the drift that left the neo-things posts off the series sidebar. A series member needs both signals: the series: key (in-post "In This Series" sidebar) and the tag (the /blog/tag/<slug>/ landing page). The check reads the slug set from data/blog_series.yml and applies only to blog posts; all current content passes. BLOGGING.md documents the both-required rule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * blog-feature-image: auto-locate native libcairo (macOS/Homebrew) compose_meta_image.py rasterizes logo SVGs via cairosvg, which dlopen()s the system libcairo by leaf name. Homebrew installs it outside the default dylib search path, so a bare `uv run` failed with a cryptic 'no library called "cairo" was found'. Add a startup shim that, when the loader can't find cairo, sets DYLD_FALLBACK_LIBRARY_PATH to the Homebrew lib dir and re-execs once (loop-guarded) so dyld picks it up — no manual env var needed. SKILL.md documents the native dependency and the brew/apt fallback. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Retire stale placeholder-meta_image references; discourage custom overrides Sweep the review-pipeline docs that still described the deleted blog-post-meta-placeholder.png flow (output-format blocker list, pre-computation image-validate candidate, seo-analyze social-meta check), and add author guidance in BLOGGING.md / AGENTS.md / the blog archetype: custom meta_image overrides are discouraged (the build-time card covers virtually every post), and a `needs-design` PR label gets a designer-made custom feature image. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Blog index: replace the committed meta image with a build-time title card Drop meta_image from blog/_index.md and delete the old meta.png; the generator now routes the /blog/ index to the plain "Blog" title card (same treatment as the case-studies and events indexes) and keeps it out of OG_SAMPLE so samples still exercise the blog post renderer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Remove the last three post meta_image overrides; designer card for /blog/ Drop the remaining custom meta_image overrides (sam-cogan-testing-best- practices, getting-started-aks-pulumi-csharp, secure-cloud-kubernetes- workloads-intro) and delete their meta.png files — the AKS post's was a byte-for-byte duplicate of 00-overview-what-were-building.png, which now appears in the post body where the workshop plan is described. Every blog post now uses the build-time card. The /blog/ index gets a committed designer-made dark "Blog" card (meta_image: meta.png) instead of the generated title card; the generator goes back to skipping it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Social: attach the titled build-time card to LinkedIn posts _meta_image_path previously returned the post's feature.png (or a legacy meta.png) — the untitled hero art — as the LinkedIn media upload. That gave feature-ful posts a title-less image on LinkedIn, while X/Bluesky show the titled build-time card via og:image on link unfurl. Point LinkedIn at that same titled card instead, so the image carries the post title everywhere. The card is a gitignored build artifact not present in the schedule-social job's checkout, but it's live at deploy time (the job runs after Build and deploy), and social_core uploads media as a multipart file rather than a URL — so fetch the deployed card to a temp file. The card is keyed by the post's directory path (matching meta-image-key.html), and a short retry absorbs post-deploy CDN lag. If the card can't be fetched, LinkedIn falls back to unfurling the link, which still renders the same titled card. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Christian Nunciato <chris@nunciato.org>


Proposed changes
To make the blog images consistent but unique moving forward I'm proposing we default to custom designed feature images with an option to use template fallbacks. (Designing the custom images will be on me.)
feature_imagein addition to themeta_image, feature images are displayed in the blog listing and on the single blog posts, meta images now are only used as meta images. (This sets us up to move to a grid layout for the blog listing.)/blog-meta-imageskill to generate feature and meta images from either the new templates or a provided custom image.Future changes
Resolves MA-542