Create hero visuals — animated GIF or static PNG — for GitHub repositories. Runs a structured discovery conversation (scan repo → recommend format → propose creative scenarios → agree on a brief), then designs bespoke HTML, previews it in the browser, and exports.
65
57%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Critical
Do not install without reviewing
Optimize this skill with Tessl
npx tessl skill review --optimize ./plugins/repo-visuals/skills/repo-visuals/SKILL.mdTurn a repo (GitHub URL, local folder, or free-text brief) into a hero visual that a viewer sees at the top of the README and instantly understands what this project does and why it's interesting. The hero may be an animated GIF or a static PNG — the skill recommends one based on the repo's identity, the user picks.
The skill's quality comes from the discovery dialog, not from templates. Every hero is bespoke.
page.screenshot to PNG (with deviceScaleFactor: 2 for retina crispness).Dev mode (author-only): Phase 6 — Evaluate exists but only runs in dev mode. Dev mode is for the skill's author iterating on the skill itself; it collects scorecard data and writes run logs under ./evaluations/ in the user's current working directory. Enable it only when the user explicitly says "dev mode" (or sets REPO_VISUALS_DEV=1). In every normal run — including Manual, Semi-auto, and Auto — the skill ends after Phase 5. Do not mention Phase 6 to end users.
Discovery runs before any HTML is written. Its job: go from a vague ask ("make a hero GIF for my repo") to a specific, committed creative brief.
Enter discovery mode whenever the user invokes the skill, unless they explicitly say "skip discovery, I have the brief ready."
Before anything else — before the scan summary, before any direction questions — ask the user which operating mode they want for this run. Use the AskUserQuestion tool so the choice is structured and visible, not buried in free text. Offer three modes; describe each in concrete terms (what gets asked, what gets decided silently) and include pros/cons so the user can pick with open eyes. Default recommendation: Semi-auto.
Note: this "operating mode" is a skill-level concept about how many questions the skill asks. It is distinct from the Claude Code harness's own auto-mode; the two do not replace each other.
Question shape:
AskUserQuestion({
questions: [{
header: "Run mode",
question: "How involved do you want to be in this run? This affects how many decisions I ask you to make before we ship an artifact.",
multiSelect: false,
options: [
{
label: "Semi-auto (Recommended)",
description: "I decide vibe, audience, scenario, dimensions, copy. You decide: output format (GIF/PNG/HTML) and one preview-and-iterate review before export. ~2 decisions. Pros: fast, keeps production-grade gate, keeps your taste in the loop on the things that matter most. Cons: you miss input on smaller creative calls."
},
{
label: "Manual",
description: "I ask you at every decision point — scenario pick, vibe confirmation, brief approval, preview iteration rounds, export ship-intent. I still make suggestions and recommendations at each step. Pros: max control, highest ceiling on quality. Cons: slow — 8–12 back-and-forths before an artifact."
},
{
label: "Auto",
description: "I make every decision and go straight to the exported artifact (GIF or PNG, my call). Pros: hands-off, 0 decisions, fastest path to a shippable draft. Cons: lower quality ceiling, more risk of missing your taste or the repo's real scope; expect to redirect after seeing the result."
}
]
}]
})Rules that apply to every mode regardless of choice (craft non-negotiables):
After the user picks a mode, commit it to memory for the run (e.g. "Mode: Semi-auto") and reference it when deciding whether to ask or decide silently at each subsequent step. In Auto and Semi-auto, make decisions with a brief one-line note ("going with the Product-UI marketing archetype per §1.4c — amplication-shape repo") so the user can redirect if they disagree.
User may provide:
gh repo view for stars/topics/languages/releases.Gather as much as possible before asking the user anything. Goal: Claude should already have an opinion about what this repo is before the vibe conversation starts.
package.json, Cargo.toml, pyproject.toml, go.mod, *.csproj, etc. — description, keywords, dependencies, entry points.assets/, docs/, .github/, any *.png / *.gif / *.svg near the root.LICENSE, CHANGELOG.md — maturity signal.ast-graph is available locally and the repo has supported languages: run scan + hotspots + symbol on top-level exports for structural inventory.src/tools/*, CLI command registrations, etc.). Do not estimate from the README. This number is used later: any hero that says "all", "every", "the whole", or shows a grid meant to represent scope must match this count — or explicitly frame itself as a sample ("10 of 30 shown", scroll affordance, "30+"). An undercount reads as a broken promise.assets//docs/, GIFs already in the README, source-level UI strings (banner generators, status string constants, hook output messages, prompt formats). Proactively ask the user for a short screen recording (.mov / .mp4) if none are in the repo — extract frames with ffmpeg -i recording.mov -vf "fps=0.5,scale=1400:-1" frames/f%02d.png and Read multiple keyframes for grounding. A generic terminal mock with invented npm run typecheck-style lines is a craft failure even when it looks polished — it doesn't match the real app and viewers who use the tool will spot it. This rule is hard, not soft: if the real UI vocabulary isn't accessible, flag the gap to the user before drafting rather than inventing.Summarize findings back to the user in ~6–10 bullets so they can correct misreadings early. Include the inventory count when one exists. If the scan finds an existing hero, branch into §1.3a before continuing to direction questions.
If the scan surfaced an existing hero, branch into the redesign protocol before §1.4. Surface the existing file (path, format, age, README placement), then AskUserQuestion the entry mode — Redesign (carry forward) / Fresh (ignore existing) / Replace in place — and follow the matching steps. Full protocol (entry-mode question, critique structure, carry-forward rules, scenario constraints) in craft/redesign.md.
Ask these as a structured batch, with suggested defaults based on what the scan found so the user can just accept or redirect:
Many users will answer "I don't know" to vibe / hero moment / audience. That's normal. Don't force them to guess — extract intent sideways:
If they still can't articulate, offer Claude's best guess based on the scan and ask them to confirm or push back. Be willing to commit first, confirm second — a concrete wrong guess triggers better reactions than another open-ended question.
Before asking Q2, form an opinion from the scan. First consult craft/reference-gallery.md — try to place the target repo in one of the catalogued archetypes (Terminal-demo GIF / Product-UI marketing / Brand-first logo / Banner/promo graphic / Diagram-as-hero) and cite the match by name when recommending. If no clean match, fall back to the heuristics below.
The repo's identity tells you which format fits:
Lean static (PNG) when:
assets/ / docs/ are already static and strong.Lean animated (GIF) when:
Lean HTML-only when:
Present the recommendation forcefully: "Based on the scan, I'd go static — this repo's identity is [X], and motion would add noise not signal. Want me to proceed with static, or would you rather animated?" Then honor whatever they pick.
Mascot / character-driven repos (pixel pet, animal, robot, bespoke creature) are a special case worth flagging at recommendation time:
Offer 2–3 concrete scenarios (two if the viable directions are closely related, three if they diverge meaningfully), each with:
htop")Then Claude's recommendation: pick one and argue for it forcefully in 1–2 sentences. Frame it as something the user can still redirect.
Move to the build phase when all six are settled:
Write the brief back to the user in a compact block. Wait for "go" before writing any HTML — unless the mode is Auto, in which case proceed directly to Phase 2 with a brief summary line and no wait. In Semi-auto, show the brief but proceed after a brief pause unless the user interjects. In Manual, wait explicitly for "go".
Default: 1200×675 (16:9). It's the safe pick when the repo gives no strong signal — GitHub's ~1000px README column renders it at ~560h (comfortable but not dominant), and the skill's capture/eval scripts are calibrated around that width. Start here unless the repo wants something else.
Tailor when the repo's spirit points elsewhere. Don't force a 16:9 crop onto a project whose identity is clearly another shape. Signals to deviate:
How to decide: during the scan (§1.3), note the existing hero image's dimensions and the repo's format archetype (from craft/reference-gallery.md). If they point toward a non-16:9 shape and the brief's hero moment fits that shape, propose the tailored size in the direction-questions batch (§1.4) — show the user the default and the tailored option, cite the reason, let them pick. If nothing argues against 1200×675, don't introduce the choice; just use it.
Craft rules scale with whatever dimensions are chosen — the font-size floors, bottom-clearance minimums, and column-density rules later in this document are written around 1200×675 but are expressed as ratios (% of stage height, px relative to canvas width) so they port. When you deviate, recompute: e.g. at 1200×400 the body-text floor is still ~2.5% of stage height × retina headroom, not a fixed 17px.
The capture pipeline already supports arbitrary dimensions — scripts/screenshot.js and capture.js both take --width and --height flags. Pass whatever the brief locked in; don't hardcode 1200×675 in export commands.
Run after the brief block is written, before saying "go" (Auto: silently; Semi-auto: silently, surface only if it triggers a revision; Manual: visible note the user can override).
Scope of this gate is deliberately narrow: only repo-context fidelity. A hero can look polished and still say the wrong thing about this specific repo — that's what Gate A catches. Aesthetic judgments, AI-design clichés, technical compliance, "is the design generic" — all out of scope. Those belong to taste and craft rules elsewhere in this document, not to a gate that triggers a revision. Keeping the scope narrow is what prevents the gate from drifting into "optimize for pretty" — the failure mode the original Reddit feedback warned about.
Inputs (assemble from §1.3 scan + the locked brief):
Critique prompt:
You are critiquing a draft creative brief for the repo
<owner/repo>'s hero visual before any HTML exists. Your only job is to check whether the brief faithfully represents this repo's own positioning — not to judge aesthetics, not to suggest design improvements.Brief:
<paste the locked brief>Repo ground truth:
<README excerpt, inventory count, stated hero moment, audience, "what NOT to imply">Answer concretely (cite the brief and the README):
- Voice match. Does the brief's on-screen copy use this repo's own README phrasing and terminology, or does it drift into generic marketing voice?
- Scope honesty. If the brief implies "all" / "every" / a grid, does it match the real inventory count? If not, is it explicitly framed as a sample?
- What it implies that it shouldn't. Walk the "what NOT to imply" list and the README's actual positioning — does the brief accidentally suggest something the repo isn't claiming?
For each, output:
PASS(with a one-line reason), orFAIL(with a one-line reason and a one-line concrete fix). Do not comment on visual style, color, layout, or design quality — those are not what this gate checks.
What to do with the result:
Once the brief is locked and the user says "go", write the HTML in one file (index.html in a working directory for this repo's hero).
Default layout — always nest per-repo under a subdirectory named after the target repo (e.g. last30days-skill, my-cli):
<current-dir>/repo-visuals-work/<repo-name>/
index.html # the hero animation source
assets/ # any images/SVGs the scenario needsUse repo-visuals-work/<repo-name>/ so the scratch files stay obviously separate from the target repo and runs for different repos don't clobber each other. Never write directly into repo-visuals-work/ — always into the repo-named subfolder. If no obvious repo name, use a short slug derived from the brief.
Open the target repo's README once more right before writing HTML. Mirror its actual phrasing, headings, and technical terms in the animation's on-screen text. The hero should feel like it was written by the repo author, not for them.
Before writing any scene copy or layout, read:
craft/headlines.md — headline patterns (imperative-plus-invariant, narrative arc), voice rules, anti-patterns.craft/templates/*.html — full working heroes from past runs, all upstream-merged (the maintainers of the target repos accepted them). Read end-to-end to see how a complete scene system is composed (stage + browser chrome + tool-body + rotating hero text + progress indicator + timeline scheduler). Don't copy verbatim — steal patterns. Match by archetype, not by preference ranking.Every scene needs a headline. A demo without copy delivers no meaning.
index.htmlSingle self-contained file. No build step. Sections:
@import), define CSS custom properties for the palette (--bg, --accent, --text, --muted, etc.) derived from the vibe/constraints.TIMELINE with named keys (e.g. scene2Start: 3500) so pacing is tweakable in one spot. Include loopPauseAt so the animation has a clean loop boundary.schedule(t, fn) wrapping setTimeout into an animTimers array, plus a runLoop() that clears and restarts. This is what the export pipeline calls to reset to t=0 deterministically.transform and opacity only — never top/left/width/height (janky, expensive).runLoop() is the hard reset if needed.Math.random() without a seed, no Date.now()-based logic. Everything must replay identically each capture.<next lower round number>+ ("40+ rules", "6k+ stars") when a number helps the pitch. Full banned/allowed list and soft-cap reasoning in craft/rules.md.npm run typecheck-style lines, generic $ shell prompts, made-up status indicators all read as a hollow simulation to anyone who actually uses the tool. Pull real strings from screenshots, repo source (status constants, hook output, banner generators), or — best of all — a screen recording the user provides. If you can't access the real vocabulary, flag the gap and ask before drafting; don't invent. This rule cost two prior runs (Terminal.Gui simulated UI, clawd-on-desk v1–v2 fake terminal) and the third (clawd-on-desk v3+) only became authentic after extracting frames from a user-supplied .mov. See also §1.3's screen-recording prompt.● thinking · reading your codebase, ● juggling · 3 subagents in parallel) feels like the repo's own activity log. See craft/headlines.md..form .row, not bare .row) so they don't leak into the rest of the stage.craft/rules.md.(0, 0), treat box-shadow as preview-only, never let content exceed the stage, always pass an explicit clip to page.screenshot(), and visually diff the export against the HTML before declaring done. Detail in craft/rules.md.deviceScaleFactor: 2; GIF via the zoom-fallback in craft/export.md). Source font floor on a 1200-wide canvas is ~15.5 px body / ~12.5 px metadata after GitHub's ~0.83× downscale. The own benchmark is "looks like a native MacBook retina screenshot" sitting next to other chrome on the README.craft/rules.md.First preview as soon as:
Don't polish before first preview. User's reaction on overall shape is more valuable than Claude's local polish loop.
Once index.html is ready and §2.5's stop conditions are met, run a vision-based check on the rendered HTML before any GIF/PNG export. Same narrow scope as Gate A — only repo-context fidelity (does what's on screen match what the README says about this repo?). Aesthetic, technical, and craft compliance are explicitly out of scope; those are caught by taste and the dev-mode scorecard, not by an iteration-triggering gate.
This catches the brief→pixels gap: the right brief can still produce text that drifted from README phrasing, a scene that undercounts the repo's real inventory, or copy that quietly implies something the "what NOT to imply" list ruled out.
Why on HTML, not the exported artifact: an export cycle is expensive (GIF: capture + ffmpeg ~30s+, PNG: Puppeteer ~3s but still wasted if the critique fails). Running the check on Puppeteer screenshots of the HTML keeps it in the same cheap loop as build, so an iteration is "edit HTML, re-screenshot, re-critique" — no encoder in the inner loop.
Mode interaction:
| Mode | Gate B behavior |
|---|---|
| Auto | Run silently. If FAIL, apply 1 auto-iteration (edit HTML, re-screenshot, re-critique). After 1 retry, proceed regardless and note remaining issues in the hand-off. |
| Semi-auto | Run once silently before showing the artifact. If FAIL, apply 1 auto-iteration before the human preview. Surface a one-line "Gate B caught and fixed: [X]" so the user knows. |
| Manual | Skip — the human is the critic. Optional: offer to run it as a "second opinion" if the user asks. |
Capture step (no ffmpeg):
scripts/screenshot.js 4–5 times at evenly-spaced --seek values across the loop duration (the script uses window.seekTo(t) if exposed by the HTML; otherwise design the HTML to expose it — see §2.3 timeline helpers). Output to repo-visuals-work/<repo>/critique-frames/.scripts/screenshot.js call at deviceScaleFactor: 2.Critique prompt — narrowed version of §6.3, repo-context only:
You are checking the rendered hero for
<owner/repo>against the repo's own positioning. Only judge whether what's on screen matches the README — not whether it looks good, not whether the design is original, not whether type is well-set. Aesthetic and craft judgments are out of scope here.Repo ground truth:
<README first 40 lines, real inventory count, stated hero moment, audience, "what NOT to imply" list>For each frame, rate (1–5, default 3, evidence required to move):
- Voice match. Does on-screen text use README phrasing and terminology, or drift to generic marketing voice?
- Intent delivery. Does the hero deliver the why a viewer would reach for this repo, grounded in what the README claims — not just what the repo does?
Also flag binary issues (PASS/FAIL):
- Scope undercount. Does any "all" / "every" / grid claim match the real inventory? If not, is it explicitly framed as a sample?
- Don't-imply violations. Does anything on screen suggest something from the "what NOT to imply" list?
Cite specific frames in every observation. Do not comment on color, layout, animation polish, or design taste.
Pass/fail rule (narrowed):
Aesthetic / legibility / loop-duration / palette concerns are not Gate B's job. They surface in the dev-mode scorecard (§6) and as user-visible feedback in Phase 3, but they don't trigger the retry. This keeps Gate B from manufacturing busywork on artifacts that are visually fine but technically borderline (real incident: the original 28s clawd-on-desk hero would have triggered a Code-row FAIL on loop duration, the resulting fix was perceptually invisible — the gate did nothing useful).
On fail, exactly one retry: identify the most-cited concrete repo-context problem from the critique notes (not all of them — that invites whiplash). Edit the HTML to fix that one thing. Re-screenshot. Re-critique. After the retry, proceed to Phase 3 (Semi-auto) or Phase 4 (Auto) regardless of the second result — log remaining issues for the user.
Why one retry, not many: the critic and the generator are the same model. More than one auto-iteration risks sycophantic loops or whiplash between two equally-flawed designs. One retry forces a single decisive fix and stops.
Keep this phase conversational. The goal is to converge on a version the user loves before spending time on export.
After writing index.html, give the user the command to open it themselves (their browser, their timing):
start repo-visuals-work/<repo-name>/index.htmlopen repo-visuals-work/<repo-name>/index.htmlxdg-open repo-visuals-work/<repo-name>/index.htmlTell them to watch one full loop (the animation restarts automatically via runLoop()).
Keep first-preview questions focused on shape, not polish:
Don't ask about colors/fonts/spacing on the first round. Polish comes after shape is right.
frontend-design. If the user has gone back-and-forth on style (palette, type, overall aesthetic, visual language) for 3+ rounds without converging — or says something like "still not it" / "try a totally different direction" — stop tweaking in place. Invoke the frontend-design skill via the Skill tool to get a fresh, high-quality design pass. Pass it the brief, the repo scan summary, the current index.html, and a plain-language description of what's not working. Use its output as the new starting point, then return to this iteration loop. Don't invoke it for pacing, timing, or animation-logic feedback — only when the blocker is visual design quality.GIF quantization causes specific failures that HTML preview hides: small text blurs, near-identical hues posterize, fine gradients band. If GIF was selected in §1.4, run the export pipeline once at ~70% polish so these surface before the final polish rounds. Check:
If problems appear, tune the HTML (bigger type, fewer palette neighbors, simpler gradients) and keep iterating on the preview.
Skip this section entirely if the output is not a GIF (MP4/WebM preserve HTML fidelity; static outputs are sampled directly).
Stop iterating when the user says "ship it" (or equivalent). Don't invite more rounds — excess polish is real cost. If Claude thinks there's still a clear improvement available, mention it once and let the user decide.
The user may not fully know what they want. Keep watching for mismatches between the scan/brief and the HTML behavior:
When you spot a mismatch, flag it proactively ("the README leans 'fast' but the current pacing is slower — intentional, or should we tighten?"). Deliver intent, not just instructions.
"Reduce" means reduce — directional verbs are load-bearing. When the user pairs a directional verb (reduce, smaller, tighten, cut, shrink, trim) with a relational clause ("so A equals B", "to match X"), treat the directional verb as the binding constraint. If executing the relational clause would violate the direction — e.g., equalizing padding by growing the demo — stop and restate rather than execute. Incident detail in craft/rules.md.
Before you export anything, confirm — the exact gate depends on operating mode (§1.1a):
| Gate item | Manual | Semi-auto | Auto |
|---|---|---|---|
| User has seen the artifact running (open in browser or rendered screenshot) | required | required | skipped |
| At least one iteration round after first look | required | required | skipped |
| Scope match — hero claims ("all", "every", grid/list representing the repo) match real inventory from §1.3, or explicitly framed as sample ("10 of 30", "30+", scroll affordance) | required | required | required |
| User has explicitly said ship / go / export | required | required (after 1 preview) | not required |
The scope-match rule is non-negotiable in every mode — it's a craft check, not a human-involvement question. The human-in-the-loop items are what modes toggle.
Export is the last step, not a midpoint. A capture→encode→evaluate cycle feels productive but burns the user's patience on a draft that wasn't ready. When in doubt between "export this pass" and "one more iteration", prefer the iteration — except in Auto mode, where the point is to deliver a first draft fast and let the user redirect.
Check presence, list missing, ask the user before installing:
puppeteer — via node --version and looking for node_modules/puppeteer. If missing: npm install puppeteer (~170MB Chromium download).ffmpeg — via ffmpeg -version. If missing:
choco install ffmpeg, brew install ffmpeg, apt install ffmpeg) — needs admin.https://github.com/GyanD/codexffmpeg/releases/latest and extract ffmpeg.exe into the skill's bin/ dir. Do NOT add to PATH; call by absolute path.Never install silently. Show the plan, ask, then act.
Based on the format decided in §1.4c:
craft/export.md.craft/export.md.repo-visuals-work/<repo-name>/index.html.scripts/capture.js (GIF) and scripts/screenshot.js (PNG) wrap the recipes; both default to 2× retina and accept --width / --height. Don't hardcode 1200×675 in invocations — pass what the brief locked in.
repo-visuals-work/<repo-name>/hero.gifrepo-visuals-work/<repo-name>/hero.pngKeep in the scratch dir until Phase 5 (Output) moves it.
Move hero.gif / hero.png from the scratch dir into the target repo, update the README, optionally open a PR. Full mechanics in craft/ship.md. Decision-tree headlines:
assets/ → docs/ → .github/ → default assets/hero.gif); ask before creating dirs. Default to image + README line only — no hero.html, no maintenance docs, unless the reviewer asks, the repo has precedent, or the user opts in. (Premature source-bundling is a top reviewer complaint — see craft/ship.md for incident links.)<repo-name> demo. Always use relative paths — never raw.githubusercontent.com/..., even if the rest of the README does (legacy debt; doesn't render in forks/PR previews).docs/add-hero-gif unless repo convention differs. Co-author footer default OFF — only on explicit opt-in. Provenance footer default ON for hero PRs — append > Generated with [repo-visuals](https://github.com/livlign/claude-skills) — happy to iterate on changes. as the last line of the PR body, and verify it's there in a pre-flight check before gh pr create. Skip only when target culture argues against (AI-PR ban in CONTRIBUTING) or it's a non-hero PR. Cannot be retrofitted post-merge — get it right at submission. User-owns-repo → push to origin; doesn't-own → gh repo fork --clone=false then gh pr create --repo <upstream> --head <user>:<branch>. Not authed correctly → stop and ask.SHOWCASE.md invite — never let it crowd the hero hand-off, never re-surface it.repo-visuals-work/<repo-name>/ and print the path; don't touch the target repo.Read craft/ship.md end-to-end before running this phase the first time on a given repo.
Gate: run this phase only when dev mode is active (user said "dev mode" this run, or REPO_VISUALS_DEV=1). In every other run — Manual, Semi-auto, Auto — stop after Phase 5. Do not ask user-rating questions, do not write run logs, do not mention this phase.
In dev mode, score the final artifact (not the process) across four rater types — User (3 rows), Claude (1 row), Code (auto via scripts/evaluate.js), AI (vision pass on extracted keyframes, blind to prior chat). Use the labeled 1–5 scale (5 / Excellent style). Skip User rows in Auto mode and flag accordingly.
Write run logs to ./evaluations/runs/<YYYY-MM-DD>-<slug>.md in the user's working directory (NOT the plugin cache — wiped on /plugin update). Curated rolling stats live in ./evaluations/index.md, edited by the repo-visuals-retro meta-skill.
Full criteria tables, the fixed AI-eval prompt (with anchored ground-truth and the "default to 3, lower-by-one if you can name an improvement" protocol), the AskUserQuestion shape for User rows, and the scorecard template all live in craft/evaluate.md. Read it before running this phase.
90aa043
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.