Generative Assets · Industry Demos IV

Making Alabaster Dental Studio

A conversion-focused landing page for a fictional South Perth dental practice — dentistry sold by removing fear, priced out loud, with a procedural tooth map instead of a stock-photo smile.

Concept

Alabaster Dental Studio is the stone the enamel aspires to: a family & cosmetic practice for adults who have put the checkup off for two years, parents booking kids in, and professionals weighing whitening against a chipped front tooth. The page has one job — book a checkup — and it does it by killing the two things that stop people booking: fear of the chair and fear of the bill.

The direction is porcelain calm: the quiet confidence of a beautifully lit studio. No bleached stock grins, no urgency banners — the $199 gap-free hook and an estimator that answers "what will this cost me?" before asking for anything in return.

Palette — argued from the chair

Porcelain#F6F4F0Ground. Enamel off-white, deliberately warmer than surgical white — a studio, not a theatre.
Graphite#2B2E33Structure and primary ink — the instrument steel. 12.5:1 on porcelain.
Rinse aqua#3E8E8BLINE/MARK only — tooth-map highlights, the zone arc, ticks. At 3.3:1 on porcelain it never sets small text.
Rinse deep#2C7370Derived CTA surface — white button text reads at 5.5:1. The aqua's job, done legibly.
Aqua ink#256965Derived body-safe aqua for eyebrows, links and map labels — 5.9:1 on porcelain.
Blush coral#C96F5EGum-tone warmth: focus rings, the gum halo behind the arch, one accent moment per section.
Coral ink#9C4A3BDerived body-safe coral (5.6:1) — card eyebrows and error text, so the warm tone can speak in small sizes.

The spec names rinse aqua as the accent; the ink/line split (LEARNINGS W2/W5) means it stays a line-and-mark colour. Everywhere aqua needs to carry text or a button, a darker sibling was derived and contrast-checked rather than letting the mark colour fail at 3.3:1.

Type

Bricolage Grotesque (display, optical size active, set tight at −.015em) carries the studio confidence — contemporary without being cold, and its slightly humanist forms keep "Dentistry without the dread." from reading like a bank. Inter does the clinical work: body, UI, forms — and every price is set with font-variant-numeric: tabular-nums so $199, $190–$380 and $1,700 align like an honest invoice.

The signature — Tooth-Map Estimator

The upper arch is generated at runtime as pure SVG — no raster, no library. Sixteen crowns are placed along a blended curve y = 58 + 188·(0.62u² + 0.38u⁴): the quartic term flattens the anterior curve and steepens the molar arms, which is what a real dental arch does. The curve is sampled 800 times to build an arc-length table; each tooth's centre is placed by cumulative crown width (molars 44 px wide down to lateral incisors at 27 px), then rotated to the local tangent. Crowns are rounded paths with per-type occlusal grooves — an H-pattern for molars, a single fissure for premolars, a ridge for canines — filled with a radial porcelain gradient and a specular gleam.

Every tooth is a keyboard-reachable control: role="button" tabindex="0" with a per-tooth aria-label ("Tooth 14 — upper left second molar…"), Enter/Space handlers, and a live region announcing each selection. Concern chips (checkup / chip / toothache / whitening / wisdom) light zones on the arch; tapping a tooth infers the concern from its anatomy — third molars route to wisdom, incisors to chip repair, load-bearing teeth to toothache. The aqua zone arc under the crowns is one path whose six-value stroke-dasharray is recomputed per zone (two dash segments cover the split wisdom zone), animated by a CSS transition. Selecting whitening literally brightens the smile-zone gradient a shade — the second-read detail.

Every card ends the same way: an honest price anchor, an honesty line ("root canal $950–$1,700 — quoted after x-rays, never off a webpage"), and a Book this button that pre-fills the enquiry form with the concern — the estimator warms the lead instead of decorating the page.

Techniques used

Conversion decisions

Local SEO we'd implement for the real business

This demo page ships only WebPage schema naming itself a demonstration — fictional LocalBusiness or Review markup in a live index would be dishonest. For a real practice we would ship the block below, fed by their actual details and their live review stream:

<!-- would-ship markup for the real practice — NOT emitted on this demo -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Dentist",
  "name": "Alabaster Dental Studio",
  "url": "https://alabasterdental.com.au",
  "telephone": "+61 8 XXXX XXXX",
  "image": "https://alabasterdental.com.au/img/studio.jpg",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Suite X, XX Mends St",
    "addressLocality": "South Perth",
    "addressRegion": "WA",
    "postalCode": "6151",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": -31.980, "longitude": 115.861 },
  "openingHoursSpecification": [
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
      "opens": "08:00", "closes": "18:00" },
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Saturday", "opens": "08:00", "closes": "13:00" }
  ],
  "priceRange": "$$",
  "sameAs": [
    "https://g.page/alabaster-dental-studio",
    "https://www.instagram.com/alabasterdental"
  ],
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.9",
    "reviewCount": "187"
  },
  "review": [{
    "@type": "Review",
    "author": { "@type": "Person", "name": "Real Patient" },
    "reviewRating": { "@type": "Rating", "ratingValue": "5" },
    "reviewBody": "Synced from the practice's live Google reviews feed."
  }]
}
</script>

Plus: Google Business Profile with service + suburb posts, suburb-intent copy (South Perth / Como / Vic Park), FAQ schema on the real FAQ, and item-number pages for the high-intent searches ("012 013 111 121 cost Perth").

What would change for the real client

Iteration log

1Craft

  • Found by screenshot review: the first arch (pure parabola, 240 px deep on a 210 px half-width) read as a pointed "A", not a dental U — reshaped to the blended quadratic/quartic curve (188 px deep, 228 px half-width), which flattens the anterior teeth and steepens the molar arms like a real arch form.
  • The zone-arc track poked bare tails past the last molars; the visible arc is now trimmed to the toothed span.
  • Hero subline shortened so the 375×667 fold keeps h1 + CTA + trust chips; the brand line inside the h1 drops to .22em tracking under 480 px so it holds one–two clean lines.
  • Headless drive (64 asserts green): empty submit flags all 4 fields, filled submit renders the "Thanks — request received / we'd call you back" state, every chip and five sampled teeth match the independently re-derived price oracle (checkup $199, chip from $220, ache $190–$380, whitening $650–$850, wisdom from $95).

2Depth

  • Hover or keyboard-focus on any tooth now previews its name in the caption line ("Tooth 14 · upper left second molar") without changing the selection — the map teaches its own anatomy on the second read.
  • The selected tooth breathes (2.6 s, ±5 % scale) — only under html.anim, so reduced-motion users get a settled frame.
  • Whitening's bleach effect verified as a driven assert: 8 smile-zone teeth lit + brightened gradient class. Wisdom's split zone renders as two dash segments over teeth 1 and 16 — asserted, not eyeballed.
  • Screenshot review: arch reads as porcelain relief on the gum halo; card hierarchy (eyebrow → title → visit → price → honesty) survives at a glance. The same review caught a defect no state assert saw: the zone arc's leading zero-length dash, with round line caps, painted a stray aqua dot at the path start below the first molar — replaced the six-value dasharray with a four-value pattern plus stroke-dashoffset, which has no zero dashes to cap.

3Hardening

  • 375 px: scrollWidth 375, no clipped wordmark, sticky call/book bar fixed in the bottom 140 px with ≥44 px tel target; header book button stays a ≥40 px tap.
  • Reduced-motion run: html.anim never applied, hero/card/teeth all opacity 1 with the $199 rest card showing — settled and complete, not blank.
  • Chanel rule: removed the hero's second (coral) background radial — porcelain reads cleaner with one sheen source.
  • Full-page capture exposed a robustness gap: scroll reveals below the fold depend entirely on the observer, so a 6-second failsafe now adds the revealed state to everything — content can never stay hidden, whatever happens to IntersectionObserver. (The capture also taught the harness that scroll-behavior:smooth swallows rapid programmatic scroll steps — sweeps must scroll with behavior:'instant'.)
  • Final sweep: zero console errors on index and guide, exactly one h1 per page, every (08) 9xxx number on the page uses the reserved 9000 0232, no LocalBusiness/Review JSON-LD anywhere on the demo — 71 asserts green, including the estimator-vs-oracle drives and the driven-state screenshots.