A working guide to the Brightside Dental showcase โ the concept, the palette math, the type pairing, the imagery art direction, the motion system, and how to ship it. Steal freely.
Dental websites default to two failure modes: sterile (blue gradients, stock teeth, fear) or childish (cartoon molars with faces). The design brief here was a third path โ the anti-clinical clinic: light, warm, genuinely friendly, but adult.
Every decision follows from one question: "would this calm down a nervous patient?" That's why the palette is warm instead of hospital-blue, why the geometry is rounded instead of sharp, why the motion is soft and springy instead of snappy, and why the copy sounds like a person ("Words we didn't pay for") instead of a brochure ("Excellence in dental care").
#FBF6EE), not white โ the whole page sits in "afternoon light" before a single image loads.Warm white base, eucalyptus green as the trustworthy anchor, peach/apricot as the friendly accent, charcoal for text. The rule: mint and peach are accents only โ body text is always charcoal on cream/white (passes WCAG AA at 16px; #26262C on #FBF6EE is ~13.6:1).
#1F4A3C, ~11:1) or near-white at 72โ75% opacity for secondary copy โ still >7:1. Apricot #E07A3F is used for 13px+ bold uppercase labels where its ~3.2:1 ratio is acceptable for large/heavy text, never for paragraphs.| Role | Face | Why |
|---|---|---|
| Display | Bricolage Grotesque 700โ800 | A grotesque with genuine personality โ slightly quirky terminals and open counters read "friendly" without being rounded-cartoon. The variable optical size axis keeps big headlines crisp. |
| Text / UI | Inter 400โ600 | Neutral, highly legible partner that lets Bricolage carry the character. Chips, buttons, and body all use it. |
Scale: hero clamp(42px, 5.8vw, 76px), section heads clamp(32px, 4.6vw, 52px), body 16px/1.6. Letter-spacing on display is -.015em โ big friendly type still needs tightening or it drifts apart.
All photography was generated via the Higgsfield MCP โ portraits on soul_2 (natural skin, editorial light), interiors/product on nano_banana_pro. Each of the seven images came from a carefully art-directed brief โ lighting, lens, palette, composition and mood specified per shot, with one warm editorial grade repeated across all of them so seven separate generations feel like one photoshoot โ then iterated until every frame felt calm rather than clinical. The full prompt library is proprietary to the studio and available to clients on request.
filter: saturate(1.18) sepia(.38) brightness(.91) and is clipped with clip-path: inset() driven by the drag position. One asset, honest comparison mechanics, zero alignment problems.GSAP 3 + ScrollTrigger from CDN. The rule for a calm brand: nothing snaps. Everything eases with a gentle overshoot โ back.out(1.4) โ which reads as "springy but reassuring."
The recurring motif is an SVG arc (a smile) that draws itself as you scroll past it, with a dot riding the curve. Classic dash-offset technique, scrubbed:
const len = path.getTotalLength();
path.style.strokeDasharray = len;
path.style.strokeDashoffset = len; // fully hidden
gsap.timeline({
scrollTrigger: { trigger: svg, start: 'top 92%',
end: 'top 45%', scrub: .6 }
})
.to(path, { strokeDashoffset: 0, ease: 'none' }, 0)
// dot rides the arc:
.to(proxy, { t: 1, ease: 'none', onUpdate: () => {
const p = path.getPointAtLength(len * proxy.t);
dot.setAttribute('cx', p.x); dot.setAttribute('cy', p.y);
}}, 0);
The same arc appears four ways: under the word "smiling" in the hero (time-based draw on load), as two scroll-scrubbed section dividers, ghosted large behind the booking CTA, and in the logo mark. Repetition is what turns a shape into a brand.
[data-rv] element does y: 28 โ 0 with back.out(1.4), triggered once at top 88%.yPercent scrub; the hero photo scales to 1.06 as it leaves. Three layers moving at different rates = depth without gimmick.pct += (target - pct) * .18 per frame. That tiny lag is what makes it feel like a real object. It also auto-nudges once when scrolled into view so users discover it's draggable, and supports arrow keys + role="slider" for keyboard users.-4deg; a soft radial color bloom fades in from the card's bottom edge.prefers-reduced-motion and falls back to static, visible content.overflow-x: clip on html, body (plus overflow: clip on the hero) guarantees no horizontal scrollbar at any width.It's a static folder โ no build step. Two ways:
brightside-dental/ folder onto the page. Done โ you get a live URL in seconds.npm i -g netlify-cli
cd brightside-dental
netlify deploy --prod --dir .
Checklist before deploying: images compressed (each under ~350 KB here), <title> and meta description set, favicon inline (no extra request), fonts limited to two families with explicit weights.