Skip to content

DirectorySkills

Portrait switcher quotes: 1440, made in this run
Run 1Portrait switcher quotes“Add a testimonial switcher with customer photos to our agency homepage. See brief.md; headshots in photos/.”
Runs in
  • Claude Code
  • Codex
  • Cursor
  • Gemini CLI
  • GitHub Copilot
  • OpenCode
Generates with
Your agent's model
Tested with
Claude Code 2.1.322Claude Sonnet 5.51 real run, 12 Nov
Needs
Node 20+Chrome
Licence
Recaply licence

Portrait Switcher Quotes

One big centred quote with a row of small round portraits under it; choosing a portrait switches the quote.

1 view

$9.99once, yours to keep

Builds a testimonial switcher with one large quote and a row of portraits into your own project: one large centred quote on a deep indigo band, the person's name and role under it, and a row of five round portraits; the chosen portrait grows and gets a ring; arrow keys move along the row. Plain HTML, CSS and JavaScript, or matched to React, Next.js, Vue, Svelte, Astro or Tailwind when the project uses them. Comes with a working reference and a check that screenshots it at phone, tablet and desktop widths and flags sideways overflow, text under 12px, missing alt text and names, low contrast, no focus styles, motion that ignores reduced motion, leftover sample words and emoji icons. Use when a SaaS, agency or course page wants one quote at a time with faces to choose from, or someone asks for avatar tabs or a portrait switcher.

By RecaplyUpdated 12 Nov

Install Portrait Switcher Quotes

After the download, ask your agent to add it, or run the line yourself.

Read https://recaply.co/skills/portrait-switcher-quotes/install.md and follow it to install the portrait-switcher-quotes skill from portrait-switcher-quotes.zip.

Paste it into your agent. It reads our install steps, finds the ZIP you downloaded and adds the skill for you.

New to skills? How to install a skill

Similar skills

All 735 skills

Who Portrait Switcher Quotes is for

What you get

  • One HTML file with its CSS inside: no build step, no framework
  • A testimonial switcher with one large quote and a row of portraits
  • Checked at phone and desktop widths

Good fit

  • When a SaaS, agency or course page wants one quote at a time with faces to choose from

Not for

  • An app with a backend, sign-in or a database
  • Copying another company's site

About this skill

You say

Add a testimonial switcher with customer photos to our agency homepage. See brief.md; headshots in photos/.

It said back

The testimonial switcher is built and the check passes at 390, 768 and 1440px. The check covers sideways overflow, small text, alt text, names, contrast, focus styles, reduced motion, script errors, leftover sample words and emoji icons. It left one note: there is no og:image.

I looked at the 390 and 1440 screenshots. The quote, name and role read cleanly and nothing is cut off. I didn't open the 768 screenshot, and I didn't test the keyboard behaviour in a browser.

Show more

What it did in run 1

  1. portrait-switcher-quotes
  2. ls -la . photos && cat brief.md
  3. cd ./.claude/skills/portrait-switcher-quotes && cat reference/index.html reference/style.css reference/script.js; node scripts/check.mjs --ready; file ../../../photos/*.jpg; which sips
  4. S=.claude/skills/portrait-switcher-quotes && cat $S/reference/index.html $S/reference/style.css $S/reference/script.js; node $S/scripts/check.mjs --ready; sips -g pixelWidth -g pixelHeight photos/*.jpg
  5. S=.claude/skills/portrait-switcher-quotes && cat $S/reference/index.html $S/reference/style.css $S/reference/script.js; node $S/scripts/check.mjs --ready
  6. ./photos/margaret-ellis.jpg
  7. cat .claude/skills/portrait-switcher-quotes/reference/index.html .claude/skills/portrait-switcher-quotes/reference/style.css .claude/skills/portrait-switcher-quotes/reference/script.js
  8. node .claude/skills/portrait-switcher-quotes/scripts/check.mjs --ready
  9. mkdir -p img && for f in margaret-ellis daniel-osei nisha-rao tom-hargreaves; do sips -Z 288 -s format jpeg -s formatOptions 80 photos/$f.jpg --out img/$f.jpg >/dev/null; done; ls -la img
  10. ./photos/tom-hargreaves.jpg
  11. mkdir -p img; sips -Z 288 -s format jpeg -s formatOptions 80 photos/margaret-ellis.jpg --out img/margaret-ellis.jpg; sips -Z 288 -s format jpeg -s formatOptions 80 photos/daniel-osei.jpg --out img/daniel-osei.jpg; sips -Z 288 -s format jpeg -s formatOptions 80 photos/nisha-rao.jpg --out img/nisha-rao.jpg; sips -Z 288 -s format jpeg -s formatOptions 80 photos/tom-hargreaves.jpg --out img/tom-hargreaves.jpg; ls -la img
  12. cat > index.html <<'EOF' <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>What our clients say | Brightwater Digital</title> <meta name="description" content="Four Brightwater Digital clients on what a new website did for their hotel, food bank, software company and dental practice."> <meta property="og:title" content="What our clients say | Brightwater Digital"> <meta property="og:description" content="Four Brightwater Digital clients on what a new website did for their business."> <meta property="og:type" content="website"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Schibsted+Grotesk:wght@400;500;700&display=swap"> <link rel="stylesheet" href="testimonials.css"> </head> <body> <a class="skip" href="#main">Skip to content</a> <main id="main"> <section class="t-sec center" id="voices" aria-labelledby="voices-h"> <h2 id="voices-h" class="sr-only">Client testimonials</h2> <div class="wrap ps-in"> <p class="label">Brightwater clients</p> <figure class="ps-q" role="tabpanel" id="psp-0" aria-labelledby="pst-0"> <blockquote><p>Direct bookings went up by a third in the first summer. The new site finally looks the way the hotel feels.</p></blockquote> <figcaption><b>Margaret Ellis</b> · <span class="role">Owner, The Saltings Hotel, Whitby</span></figcaption> </figure> <figure class="ps-q" role="tabpanel" id="psp-1" aria-labelledby="pst-1" hidden> <blockquote><p>Volunteer sign-ups doubled after launch. Brightwater made it simple for people to help.</p></blockquote> <figcaption><b>Daniel Osei</b> · <span class="role">Director, Northside Food Bank</span></figcaption> </figure> <figure class="ps-q" role="tabpanel" id="psp-2" aria-labelledby="pst-2" hidden> <blockquote><p>They rebuilt our marketing site in five weeks. Trial sign-ups rose 41% the next month.</p></blockquote> <figcaption><b>Nisha Rao</b> · <span class="role">Founder, Ledgerly</span></figcaption> </figure> <figure class="ps-q" role="tabpanel" id="psp-3" aria-labelledby="pst-3" hidden> <blockquote><p>Patients book online now instead of phoning. Our front desk got their mornings back.</p></blockquote> <figcaption><b>Tom Hargreaves</b> · <span class="role">Hargreaves Dental, Harrogate</span></figcaption> </figure> <div class="ps-row" role="tablist" aria-label="Choose a client"> <button class="ps-t" role="tab" type="button" id="pst-0" aria-controls="psp-0" aria-selected="true" tabindex="0"><img src="photos/margaret-ellis.jpg" alt="" width="72" height="72"><span class="sr-only">Margaret Ellis</span></button> <button class="ps-t" role="tab" type="button" id="pst-1" aria-controls="psp-1" aria-selected="false" tabindex="-1"><img src="photos/daniel-osei.jpg" alt="" width="72" height="72" loading="lazy"><span class="sr-only">Daniel Osei</span></button> <button class="ps-t" role="tab" type="button" id="pst-2" aria-controls="psp-2" aria-selected="false" tabindex="-1"><img src="photos/nisha-rao.jpg" alt="" width="72" height="72" loading="lazy"><span class="sr-only">Nisha Rao</span></button> <button class="ps-t" role="tab" type="button" id="pst-3" aria-controls="psp-3" aria-selected="false" tabindex="-1"><img src="photos/tom-hargreaves.jpg" alt="" width="72" height="72" loading="lazy"><span class="sr-only">Tom Hargreaves</span></button> </div> </div> </section> </main> <script src="testimonials.js" defer></script> </body> </html> EOF cat > testimonials.css <<'EOF' :root{--bg:#1E1B4B;--ink:#F5F3FF;--muted:#C4C0E8;--accent:#F25F4C;--em:#F25F4C;--page:#fff;--font:'Schibsted Grotesk',system-ui,sans-serif} *,*::before,*::after{box-sizing:border-box} html{-webkit-text-size-adjust:100%} body{margin:0;background:var(--page);color:#1E1B4B;font-family:var(--font);font-size:1.0625rem;line-height:1.6;-webkit-font-smoothing:antialiased} img{max-width:100%;display:block} p{margin:0}blockquote,figure{margin:0} button{font:inherit;color:inherit} [hidden]{display:none!important} .sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0} .skip{position:absolute;left:-9999px;top:12px;z-index:100;background:#fff;color:#1E1B4B;padding:.6rem 1rem;border-radius:8px} .skip:focus{left:12px} :focus-visible{outline:3px solid var(--accent);outline-offset:3px;border-radius:4px} .t-sec{background:var(--bg);color:var(--ink);padding-block:clamp(64px,9vw,120px)} .wrap{width:min(100% - 40px,860px);margin-inline:auto} .ps-in{text-align:center} .label{font-size:.85rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--em);margin-bottom:.6rem} .ps-q blockquote{font-size:clamp(1.5rem,3.4vw,2.3rem);font-weight:500;line-height:1.3;letter-spacing:-.01em} .ps-q figcaption{margin-top:1.4rem;color:var(--muted)} .ps-q b{color:var(--ink)} .ps-q.in{animation:psin .35s ease} @keyframes psin{from{opacity:0}} .ps-row{display:flex;justify-content:center;align-items:center;gap:14px;margin-top:2.2rem;flex-wrap:wrap} .ps-t{width:56px;height:56px;padding:0;border:0;border-radius:50%;overflow:hidden;cursor:pointer;opacity:.7;transition:width .25s,height .25s,opacity .2s,box-shadow .2s;background:none} .ps-t img{width:100%;height:100%;object-fit:cover} .ps-t:hover{opacity:1} .ps-t[aria-selected=true]{width:72px;height:72px;opacity:1;box-shadow:0 0 0 3px var(--bg),0 0 0 6px #F5F3FF} .ps-t:focus-visible{outline:3px solid var(--accent);outline-offset:6px;border-radius:50%} @media (max-width:759px){.ps-row{flex-direction:column;gap:16px}} @media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}} EOF cat > testimonials.js <<'EOF' // Portrait tabs: choose a client to show their quote. Arrow keys, Home and End move between portraits. const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); const tabs = [...document.querySelectorAll('.ps-t')]; const panels = [...document.querySelectorAll('.ps-q')]; function select(i, focus) { tabs.forEach((t, k) => { t.setAttribute('aria-selected', String(k === i)); t.tabIndex = k === i ? 0 : -1; }); panels.forEach((p, k) => { p.hidden = k !== i; }); if (focus) tabs[i].focus(); if (!reduceMotion.matches) { panels[i].classList.remove('in'); void panels[i].offsetWidth; panels[i].classList.add('in'); } } tabs.forEach((t, i) => { t.addEventListener('click', () => select(i)); t.addEventListener('keydown', (e) => { const n = tabs.length; const j = { ArrowRight: (i + 1) % n, ArrowDown: (i + 1) % n, ArrowLeft: (i - 1 + n) % n, ArrowUp: (i - 1 + n) % n, Home: 0, End: n - 1 }[e.key]; if (j !== undefined) { e.preventDefault(); select(j, true); } }); }); EOF node .claude/skills/portrait-switcher-quotes/scripts/check.mjs index.html --out check 2>&1 | tail -40
  13. ./index.html
  14. ./testimonials.css
  15. ./testimonials.js
  16. node .claude/skills/portrait-switcher-quotes/scripts/check.mjs index.html --out check 2>&1 | tail -40
  17. ./check/390.png
  18. ./check/1440.png
  19. Done

12 Nov 2026 · Claude Code 2.1.322 with Claude Sonnet 5.5 · 1 min 20 s · $0.27 of API use

Questions

Is Portrait Switcher Quotes free?

No. Portrait Switcher Quotes costs $9.99 once and stays in your Recaply account, or it comes with the Recaply plan ($19.99 a month), which opens every premium skill and prompt.

Which agents can use Portrait Switcher Quotes?

Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode.

What do I get when I buy Portrait Switcher Quotes?

A ZIP of the whole skill folder (32 KB): the SKILL.md your agent follows and its 6 other files, the references, templates and scripts it uses. You download it from this page whenever you need it, and install it in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode. The Recaply plan opens it too, with every other premium skill and prompt.

How do I install Portrait Switcher Quotes?

Buy it, then download the ZIP from this page. For Claude Code, unzip it into .claude/skills/ in your project. For Codex, Cursor and Gemini CLI, unzip it and run npx skills add ./portrait-switcher-quotes with your agent's flag.

What do I get from Portrait Switcher Quotes?

One HTML file with its CSS inside: no build step, no framework. A testimonial switcher with one large quote and a row of portraits. Checked at phone and desktop widths.

What does Portrait Switcher Quotes need?

Node 20+ and Chrome, and no API key. Each use costs nothing beyond your agent.

How big is Portrait Switcher Quotes?

7 files, about 20,958 tokens in all. The SKILL.md is about 2,119 tokens, and your agent reads it only when the job fits.

What does a run cost?

Our 1 runs took 1 min 20 s to 1 min 20 s and $0.27 to $0.27 of API use each, in Claude Code with claude-sonnet-5-5. On a Claude plan, a run counts toward your usage instead.

Do I have to name Portrait Switcher Quotes to use it?

Type /portrait-switcher-quotes first to make sure it loads. Without it, Claude Code may judge a small job simple enough to do without the skill.