Video
![]()
![]()
Editorial hero for a report




A masonry wall of many quote cards of different lengths that fades out at the bottom, with a Show all button.
1 view
$9.99once, yours to keep
Payments are non-refundable. See our Terms of service.
Yours. Download it, then add it to your agent.
Builds a masonry wall of testimonials with a show-more control into your own project: twelve quote cards of different lengths in three masonry columns on warm white, the wall cut at 640px with a fade to the background and a Show all 12 button that opens it fully. 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 product with many testimonials wants to show volume without a long page, or someone asks for a masonry, wall-of-love or Pinterest-style testimonial wall.
By RecaplyUpdated 12 Nov
Video
![]()
![]()
Editorial hero for a report
Video1 view, 0 downloads
![]()
![]()
Lavender page for an AI app
Video
![]()
![]()
Product page for headphones
Video
![]()
![]()
Page with a node-flow hero
You say
We have loads of customer messages. Make a wall of them for our candle shop homepage. See brief.md.
It said back
The wall is built and passes the check. It shows about six cards, and a "Show all 15" button opens the rest.
All 15 reviews are in as written, each with the first name and candle from your brief. The page is one section of the homepage. It has a centred heading and three columns on desktop, two on tablet and one on phone, and it passes at 390, 768 and 1440px. The check found no overflow, small text, contrast or focus problems. I read all three screenshots. The open state ("Show fewer") isn't in the screenshots, and I didn't click it in a browser.
What it did in run 1
<li class="qw-c t${i%4+1}"><figure><blockquote><p>${e(t)}</p></blockquote><figcaption class="who"><span class="face" aria-hidden="true">${n[0]}</span><span><b>${n}</b><span class="role">${e(c)}</span></span></figcaption></figure></li>).join('\n'); fs.writeFileSync('index.html',<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Kind words from our customers | Wick & Hollow candles</title> <meta name="description" content="Fifteen reviews from Wick & Hollow customers, shared with permission."> <meta property="og:title" content="Kind words from our customers | Wick & Hollow"> <meta property="og:description" content="Fifteen reviews from Wick & Hollow customers, shared with permission."> <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=Rubik:wght@400;500;700&display=swap"> <link rel="stylesheet" href="style.css"> </head> <body> <a class="skip" href="#main">Skip to content</a> <main id="main"> <section class="t-sec" id="wall" aria-labelledby="wall-h"><div class="sec-head center"><h2 id="wall-h">Kind words from <em>our customers</em></h2><p class="sub">Fifteen notes from people who lit a Wick & Hollow candle, shared with their permission.</p></div><div class="wrap"><div class="qw closed" id="qw-list"><ul class="qw-cols"> ${li} </ul></div><p class="qw-more"><button class="btn btn-primary" type="button" aria-expanded="false" aria-controls="qw-list" data-qw>Show all 15</button></p></div></section> </main> <script src="script.js" defer></script> </body> </html> ); EOF node ../gen-work1/gen.mjs R=.claude/skills/quote-wall/reference python3 - <<'EOF' import re r='.claude/skills/quote-wall/reference/' c=open(r+'style.css').read() c=c.split('/* this design */')[0] for k,v in {'--bg:#FFFBF5':'--bg:#FAF6EA','--ink:#24201C':'--ink:#232820','--muted:#5E574F':'--muted:#59604F','--line:#EFE5D6':'--line:#E3DCC6','--accent:#C2412D':'--accent:#44684A','--em:#B23A27':'--em:#3D5F43','--t1:#FFF1E6':'--t1:#F3EAD3','--t2:#EEF6EC':'--t2:#E4EDDD','--t3:#EEF1FA':'--t3:#EDF1E3','--t4:#FBEFF4':'--t4:#F7F0DF'}.items(): c=c.replace(k,v) c=c.replace('.js .reveal{opacity:0;transform:translateY(18px);transition:opacity .7s ease,transform .7s ease}\n.js .reveal.in{opacity:1;transform:none}\n','') c=c.replace('.js .reveal{opacity:1;transform:none}','') c+='''/* this design */ .qw{--closed:430px;position:relative;overflow:hidden;transition:max-height .5s ease} .qw.closed{max-height:var(--closed)} .qw.closed::after{content:"";position:absolute;left:0;right:0;bottom:0;height:130px;background:linear-gradient(transparent,var(--bg));pointer-events:none} .qw-cols{columns:3;column-gap:16px} .qw-c{break-inside:avoid;margin-bottom:16px;border-radius:18px;padding:1.3rem} .qw-c figure{display:flex;flex-direction:column;gap:1rem} .qw-c blockquote p{font-size:1rem} .t1{background:var(--t1)}.t2{background:var(--t2)}.t3{background:var(--t3)}.t4{background:var(--t4)} .qw-c .face{width:40px;height:40px;display:grid;place-items:center;background:var(--accent);color:var(--on-accent);font-weight:700;font-size:1rem} .qw-more{text-align:center;margin-top:1.4rem} .qw .qw-cols{padding-bottom:1px} @media (max-width:1000px){.qw{--closed:600px}.qw-cols{columns:2}} @media (max-width:760px){.qw{--closed:860px}.qw-cols{columns:1}.btn{min-height:48px}} ''' open('style.css','w').write(c) EOF cat > script.js <<'EOF' // Opens and closes the wall. const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); const qw = document.getElementById('qw-list'); const qb = document.querySelector('[data-qw]'); const total = qw.querySelectorAll('.qw-c').length; const closedHeight = () => parseFloat(getComputedStyle(qw).getPropertyValue('--closed')); qb.addEventListener('click', () => { const open = qb.getAttribute('aria-expanded') !== 'true'; qb.setAttribute('aria-expanded', String(open)); qb.textContent = open ? 'Show fewer' : 'Show all ' + total; if (open) { qw.style.maxHeight = closedHeight() + 'px'; qw.classList.remove('closed'); void qw.offsetHeight; qw.style.maxHeight = qw.scrollHeight + 'px'; setTimeout(() => { if (qb.getAttribute('aria-expanded') === 'true') qw.style.maxHeight = 'none'; }, reduceMotion.matches ? 0 : 520); } else { qw.style.maxHeight = qw.scrollHeight + 'px'; void qw.offsetHeight; qw.classList.add('closed'); qw.style.maxHeight = ''; if (qw.getBoundingClientRect().top < 0) qw.scrollIntoView({ behavior: reduceMotion.matches ? 'auto' : 'smooth' }); } }); EOF node .claude/skills/quote-wall/scripts/check.mjs index.html --out check 2>&1 | tail -40No. Masonry Quote Wall 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.
Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode.
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.
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 ./quote-wall with your agent's flag.
One HTML file with its CSS inside: no build step, no framework. A masonry wall of testimonials with a show-more control. Checked at phone and desktop widths.
Node 20+ and Chrome, and no API key. Each use costs nothing beyond your agent.
7 files, about 22,490 tokens in all. The SKILL.md is about 2,160 tokens, and your agent reads it only when the job fits.
Our 1 runs took 1 min 16 s to 1 min 16 s and $0.26 to $0.26 of API use each, in Claude Code with claude-sonnet-5-5. On a Claude plan, a run counts toward your usage instead.
Type /quote-wall first to make sure it loads. Without it, Claude Code may judge a small job simple enough to do without the skill.