Back to portfolio

Case study · Generative content workflow

CardNews AI

A Claude-powered CLI tool that turns a single topic into a schema-validated 10-slide visual briefing — Claude drafts the slide content as JSON, a bounded correction retry catches malformed output, and a deterministic Puppeteer rendering pipeline turns it into a reviewable 1080×1080 PNG deck plus a thumbnail grid.

Problem

Turning a topic into a visual briefing normally means doing every step by hand: framing the topic, structuring it into a sequence of slides, drafting copy for each one, formatting it consistently, rendering it to an image, and reviewing the result — one slide at a time, ten times over.

Intended user

Designed for a user who needs to turn a topic into a consistent visual briefing without manually drafting, structuring, formatting, and rendering every slide from scratch. No real marketing or communications team has adopted this — it's a working demonstration of the pipeline, run 36 times on real topics during development.

Workflow before the tool

No measured time savings are claimed here. Qualitatively: a user would research the topic, draft ten slides' worth of copy, decide on sequencing and emphasis, format each slide by hand or in a design tool, export each one, and assemble a set for review — all as separate manual steps.

What I built

How it works

Topic

Free-text CLI argument, e.g. a one-line subject.

Claude API

Drafts a 10-slide JSON structure in one call.

HTML/CSS + Puppeteer

Each slide rendered to a 1080×1080 PNG.

Human review

PNG deck + thumbnail grid reviewed before any use.

Where Claude acts, where deterministic logic acts

LLM-dependentDrafting the 10-slide JSON content from a topic (one call, plus at most one schema-correction retry)
Deterministic, no LLM involvedDeck-schema validation · HTML/CSS template selection · Puppeteer rendering · staged-directory swap · thumbnail-grid composition

Exactly one step in the whole pipeline touches a language model per run — drafting the JSON. Every step after that (validating its shape, choosing which of the 3 templates to render, producing the PNGs, assembling the grid) is plain deterministic code, which is why --render can redo all of it from a saved JSON file with no API call and no cost.

Inputs and outputs

CLI command:

npm install
export ANTHROPIC_API_KEY=...
npm start -- "Microplastics are everywhere"

Real generated output (output/microplastics-everywhere-what-we-know/cards.json, first two of ten slides):

{
  "title": "Microplastics Are Everywhere",
  "theme_color": "#1A6B8A",
  "slides": [
    {
      "slide_number": 1,
      "type": "title",
      "heading": "Microplastics Are Everywhere",
      "body": "From the deep ocean to human blood — what science
               knows, what it fears, and what comes next"
    },
    {
      "slide_number": 2,
      "type": "content",
      "heading": "What Are Microplastics?",
      "body": "Microplastics are plastic fragments smaller than 5mm.
               They come from degrading larger plastics, synthetic
               fibers in laundry, and microbeads in cosmetics."
    }
    // ... 8 more slides
  ]
}

The corresponding rendered slides:

Rendered title slide: Microplastics Are Everywhere, editorial layout with serif headline and numeral watermark
Slide 1 — title slide.
Rendered content slide: What Are Microplastics, editorial layout with a numbered circle badge, serif headline, lead/support body text, and a numeral watermark
Slide 2 — content slide.
5 by 2 thumbnail grid of all ten rendered slides for the microplastics topic, editorial layout with serif headlines and numeral watermarks
Full 5×2 thumbnail grid (diary-shot.png) — this is the fast-review artifact a user would look at first.

Tech stack

How output correctness is checked (and what isn't)

Design decisions

Correction from the source README: the repository's README and CLAUDE.md previously described the slide templates as having a "gradient background, centered white text" — stale language predating an earlier redesign. The templates actually in templates/styles.css, and the slides rendered above, use a solid white background with near-black heading text (title/content slides) and a solid theme-color background (closing slide only). Both the README and this page now describe what's actually rendered.

Adoption & documentation

Quick start:

npm install
export ANTHROPIC_API_KEY=...
npm test                              # 33 tests, no API key needed
npm start -- "<topic>"
npm start -- --render output/microplastics-everywhere-what-we-know/cards.json

Each run writes output/<topic-slug>/ containing cards.json, slide-01.png through slide-10.png, diary-shot.png, and run-metadata.json — shown above for one real example. The --render command re-renders an existing valid JSON file at no API cost.

Responsible use

Quoted directly from the project's own README:

Limitations

What I'd improve next