<aside>
I replaced a $30/month SaaS subscription with a custom-built testimonial wall using Figma Make AI, Supabase, and Claude.
The entire build took 4 hours.
👉 See it live: Darpan Dadhaniya | Senior Product Leader

</aside>
<aside>
Testimonial SaaS is a solid product.
But three things bothered me:
I wanted full control over design, data, and hosting.
| Testimonial SaaS | Self-built | |
|---|---|---|
| Monthly cost | ~$30 USD | $0 (Supabase + Figma free tiers) |
| Annual cost | ~$360 USD | $0 |
| Design control | Theme picker, colour swatches | Full custom CSS, any layout |
| Data ownership | Their Firebase (vendor lock-in) | My Supabase (portable Postgres) |
| Avatar hosting | Firebase URLs (die on cancel) | Supabase Storage (permanent) |
| Embed fit | Visible iframe seam on dark pages | Seamless #191919 background match |
| Update workflow | Dashboard UI | Edit JSON in database |
| </aside> |
<aside>
Before opening Figma Make, I spent time with Claude planning the system architecture.
The goal was to identify the simplest stack to provide a dynamic, data-driven component I could embed in Notion.
flowchart LR
subgraph Claude["Claude - Architect"]
C1["Architecture planning"]
C2["SQL scripts"]
C3["Prompt engineering"]
C4["Code review"]
end
subgraph Supabase["Supabase - Backend"]
S1["Storage bucket <br> (avatar images)"]
S2["KV store <br> (testimonial JSON)"]
S3["Edge function <br> (Deno API)"]
end
subgraph FigmaMake["Figma Make AI - Frontend"]
F1["React + Tailwind"]
F2["Masonry grid"]
F3["Scroll animation"]
end
subgraph Notion["Notion - Host"]
N1["Dark mode portfolio"]
end
C1 -->|"Plans stack"| Supabase
C3 -->|"Drafts prompts"| FigmaMake
C4 -->|"Reviews output"| FigmaMake
C2 -->|"Writes setup"| Supabase
S1 -->|"Permanent avatar URLs"| S3
S2 -->|"JSON array"| S3
S3 -->|"REST API"| F1
F1 --> F2
F2 --> F3
F3 -->|"Published embed"| N1
https://github.com/darpandadhaniya/wall-of-love
</aside>
<aside>
This section shows the actual AI prompts I used, what they produced, and how I refined the output. Each prompt demonstrates a specific aspect of working with AI effectively: providing context, decomposing complexity, and iterating based on visual feedback.
Before any design work, I gave Figma Make a project brief. This front-loads the constraints so every subsequent prompt inherits the same design system.
I'm building a testimonial "Wall of Love" component inspired by Testimonial SaaS's masonry animated format. It will be embedded in a Notion portfolio page forced to dark mode (background #191919).
The wall is a responsive masonry grid of testimonial cards that scroll vertically in a continuous, very slow animation. Columns scroll in alternating directions - up, down, up, down. Animation pauses on hover.
Card design: circular avatar, name, optional job title, 5 orange stars, body text, "Show more" link for long reviews. Cards have a coloured left border accent and solid orange offset shadow.
Constraints: dark mode only, #191919 background, 100% width, 650px fixed height, responsive 4→3→2→1 columns, very slow scroll (~60s per cycle), no headers or branding.
Why this works: The brief establishes the target (Testimonial SaaS's format), the constraint (Notion dark mode), the card anatomy, and the responsive behaviour - all in one message. Every follow-up prompt can focus on one detail without re-establishing the full context.
Build a single testimonial card matching the attached screenshot and the design specs in the context above. Make two versions side by side: one with a short testimonial (2 lines) and one with a long testimonial (7+ lines that truncates with "Show more").

What I refined: The initial output used a soft glow shadow. My Testimonial SaaS reference uses a solid hard-edge offset shadow. I followed up with: "Replace any soft glow or blur shadow with a solid #FFA500 orange block offset 4px right and 4px down. No blur, no transparency - a clean hard-edge offset shadow."
The lesson: AI tools default to conventional design patterns (soft shadows). Reference images and specific language ("hard-edge", "no blur") override those defaults.
Stack 8 of these cards in a single vertical column with a 12px gap. Mix short, medium, and long testimonials. Duplicate the full stack underneath for a seamless scroll loop. Animate the column scrolling upward - very slow, 60 seconds per full cycle, linear timing. Pause on hover. Wrap in a 650px container with overflow hidden and #191919 background.
Key technical detail: The infinite scroll works by duplicating the card stack. The CSS animation moves the entire column upward by exactly 50% (the height of one complete set), then instantly resets to 0. Because both halves are identical, the reset is invisible. The speed is calculated dynamically: duration = (container height / 2) / 30px per second. This keeps the scroll speed consistent regardless of content length.

Place multiple scrolling columns side by side. Use CSS grid with auto-fill and a minimum card width so the column count adapts to screen width. Columns 1 and 3 scroll up, columns 2 and 4 scroll down. The horizontal spacing between columns should be fluid - distribute remaining space evenly.

What I refined: The first draft used fixed card widths that didn't match Testimonial SaaS's fluid behaviour. Comparing screenshots side by side, I noticed Testimonial SaaS keeps card width constant and varies the horizontal gap. The fix: justify-content: space-evenly with fixed column widths, letting the gaps absorb the extra space.
Add 60px gradient fade masks at top and bottom (#191919 to transparent). Background must be exactly #191919 with zero outer margin, padding, or border. The component edges must be invisible inside the Notion embed iframe.
Why #191919 matters: Notion's dark mode background is exactly #191919. Even one shade off (#1A1A1A or #181818) creates a visible line where the embed iframe meets the page. I confirmed this hex value through documentation and testing before committing to it.

</aside>
<aside>
</aside>
<aside>
</aside>
<aside>
</aside>