Guide · Industry demo · Chiropractic
How Atlas Chiropractic was built
A fictional independent chiropractic clinic in Mount Hawthorn, built as a conversion-first landing page for the patient with a neck that clicks or a back that "goes". The page has one job — book the initial consult — and one differentiator stated everywhere it matters: no lock-in care plans, pay per visit.
The concept
Allied-health demos live or die on trust, so the signature sells honesty rather than urgency. The Spine Map is a full posterior spine drawn vertebra by vertebra in SVG; five complaint chips light the typical region in amber, annotate it in plain clinical language, and swap a care card showing exactly what the first visit involves and costs — $120 standard initial, $150 for the sciatica workup, $85 for kids. The map carries its own disclaimer ("typical patterns, illustrative — yours is assessed in the room") and every card repeats the no-lock-in line, the imaging declaration and the health-fund gap declaration. The chosen complaint pre-fills the booking form.
Palette — eucalypt calm
The quiet clinic, not the cracking-video channel. Every colour is argued from the room: sage walls, one plant, warm light on the region that matters.
Type
Bricolage Grotesque (600) carries the display — humanist warmth over clinical bones, which is the whole brand argument in one face. The vertebra labels (C1 · T6 · L5) are set in it inside the SVG, so the spine speaks the site's own typography. Figtree handles body copy: open, legible, unfussy at 16.5px.
Techniques
- Procedural spine. All 25 vertebra paths (7 cervical, 12 thoracic, 5 lumbar, sacrum) are generated in JS from a small geometry table — rounded body, transverse-process wings, a spinous-process dot — so widths and spacing grade naturally down the column. No raster, no hand-drawn paths.
- Dash-draw entrance. Each path's dasharray/dashoffset is set to its measured length and revealed in sequence (~110 ms per element, 52 ms stagger). Every stroke stays
visibility:hiddenuntil its drawn length is > 0 — round line-caps otherwise render a stray dot at the path start before anything draws. - Token-invalidated highlight engine. One persistent rAF loop drives the amber region: each chip handler bumps a token and swaps the active-region object before any animation state changes, so rapid-fire chip taps can never leave a stale closure writing into a dead region. The pulse floor never drops below 0.55 opacity — the signature is visibly lit at any screenshot instant — and the per-vertebra phase offset makes the pulse travel gently down the region.
- Dual-speed redraw. The first activation gets entrance choreography (420 ms, 70 ms stagger); every later chip swap re-lights snappy (190 ms, 14 ms stagger) so the map feels instant, not laggy.
- Fee lookup, no arithmetic. The care card is a straight lookup of the pinned fee schedule — nothing computed, nothing to round — and the grid floor ("visits from $50") is the cheapest fee on the page, so the page never argues with itself.
- Accessibility mirror. The SVG data is mirrored as a visually-quiet plain-text list under the map; chips are real buttons (Enter and Space both drive them); each vertebra carries a native
<title>tooltip; reduced-motion gets an instant, statically-lit spine.
The fee schedule (as pinned)
| Visit | Fee | Notes |
|---|---|---|
| Initial consult & assessment (45 min) | $120 | Neck, desk and lower-back chips resolve here |
| Complex initial — sciatica & nerve (60 min) | $150 | Nerve-pattern workup included |
| Kids & teens initial (under 16) | $85 | Low-force, parent in the room |
| Standard adjustment visit | $65 | Dry needling within a visit +$25 |
| Extended visit (30 min) | $95 | Multi-region or flare-up |
| Concession & seniors standard | $55 | |
| Kids standard | $50 | The page's "visits from $50" floor |
| Imaging | — | Only when clinically indicated; referred out, bulk-billed where eligible — a designed price-less line |
Two declarations print no number by design: imaging (clinical indication decides it) and health-fund gaps (HICAPS on the spot; the gap depends on the fund). Both appear on the care card and in the fees section — the declaration is the honest deliverable.
Conversion decisions
- Fees above the fold of trust. For allied health the pricing page IS the trust strip — publishing every fee, plus "no lock-in care plans" as the first trust chip, converts the sceptic the cracking-video channels created.
- The signature feeds the form. Tapping a complaint pre-selects the matching "what's going on" chip in the booking form, so the enquiry arrives warmer and the visitor never re-enters what they already told the page.
- Booking CTA carries the price. "Book an initial consult — $120" — naming the number in the button removes the last unknown before the tap.
- Form fields. Name, phone, suburb, complaint chips, preferred time — enough for the front desk to call back usefully, few enough to finish on a phone. Confirmation is a designed local panel (hidden until a valid submit); the demo never fakes a network round-trip.
- Mobile sticky bar. Call + book, both thumb-height, on every viewport under 720px — most "my back just went" traffic is a phone held at an awkward angle.
Local SEO we'd implement for the real business
The demo page itself carries only honest WebPage/CreativeWork schema — fictional structured data in a real index would be dishonest markup. For a real clinic we'd ship:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "MedicalClinic",
"name": "Atlas Chiropractic",
"description": "Independent chiropractic clinic in Mount Hawthorn, Perth.
No lock-in care plans — pay per visit.",
"url": "https://atlaschiropractic.com.au",
"telephone": "+61 8 XXXX XXXX",
"address": {
"@type": "PostalAddress",
"addressLocality": "Mount Hawthorn",
"addressRegion": "WA",
"postalCode": "6016",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -31.92, "longitude": 115.835 },
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "07:30", "closes": "18:30" },
{ "@type": "OpeningHoursSpecification",
"dayOfWeek": "Saturday", "opens": "08:00", "closes": "12:00" }
],
"medicalSpecialty": "Chiropractic",
"priceRange": "$50–$150",
"areaServed": ["Mount Hawthorn","Leederville","North Perth",
"Glendalough","Coolbinia"],
"review": {
"@type": "Review",
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"author": { "@type": "Person", "name": "— a real patient —" },
"reviewBody": "— their words, used with permission —"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9", "reviewCount": "— live count —"
}
}
</script>Why the top-level type is MedicalClinic: schema.org has no chiropractic organization type. The tempting token — Chiropractic — is a MedicalSpecialty enumeration value, not a business type; using it as the top-level @type is invalid organization markup (a trap this collection has hit before, on a podiatry build). It belongs exactly where it appears above: as the value of the medicalSpecialty property on a MedicalClinic. Review and rating markup would be fed from the clinic's real Google reviews, never authored by hand.
What changes for the real clinic
- Bookings: the form hands off to their practice-management system — Cliniko, Nookal or HotDoc are the usual suspects in WA allied health — so the "preferred time" field becomes a live diary.
- Payments & claims: the HICAPS/Tyro terminal declaration stays, but wired to their actual fund list and item codes (initial 1001, standard 1004).
- Reviews: the demo copy is replaced by their Google reviews feed, marked up per the panel above.
- Registration: the placeholder Reg. CHI0000 becomes the practitioner's real AHPRA registration number, and the practitioner's name, photo and bio join the trust strip.
Iteration log
Pass 1 — Craft. Read the rendered page, not the code
- The first-render spine read as a string of beads — vertebra bodies too small against their spacing. Widened every body ~35% (cervical 40→wider grade, lumbar to 74–83 viewBox units), lifted stroke weight 2→2.2, and bumped the in-SVG labels 11→15 units so C1/T6/L5 are legible at the rendered 150px column width.
- The masthead "Book a visit" button wrapped to two lines at 375px — the classic mobile-header collision, caught on screenshot while every geometry assert stayed green. Fixed with white-space:nowrap on buttons; header edges re-measured clean (wordmark 197 / call 217–243 / button 253–362).
- Amber discipline: review stars and the Sapience-band CTA had drifted onto amber. Both moved to green — amber is the lit region and annotation marks only, as pinned.
- Map road-labels darkened (#7A8D87 → #5C6B64) for contrast; skull hint simplified to a single clean dome arc; the phone pattern rewritten v-flag-safe (escaped parens and hyphen).
Pass 2 — Depth. Enrich the signature
- Every vertebra now carries a native SVG <title> — hover C1 and it names itself "the atlas, carrying the skull"; C2 "the axis". A second-read detail that doubles as a11y.
- The region pulse got a per-vertebra phase offset, so the amber breathes down the region like a slow wave instead of blinking as a block — floor held at ≥0.55 opacity so the thumbnail can never catch it dark.
- Chips press (scale .96) on tap; the annotation card glides between anchor heights on a crafted cubic-bezier rather than jumping.
- Verified the fee lookup against the pinned schedule by driving all five chips by mouse and keyboard: 120 / 120 / 120 / 150 / 85, form radio pre-filled each time, grid floor "from $50" cross-checked.
Pass 3 — Hardening. 375px, keyboard, rapid-fire, reduced motion
- Full sweep at 375×812: no horizontal overflow (scrollWidth 375), masthead collision-free, h1 + priced CTA above the fold, sticky call bar inside the bottom 140px, tap targets ≥44px.
- Rapid-fire drive — all five chips dispatched in one evaluate, twice over, no settle between — landed consistently on the last chip with exactly three highlights lit and no stale-closure writes, thanks to the in-handler token bump.
- Reduced-motion path: spine renders instantly drawn, region statically lit at 0.8 opacity, settled flag true immediately; zero console errors.
- Chanel rule: removed the unused amber-soft token and a dead transform transition from the button styles; final copy read tightened the FAQ answers and confirmed both price-less declarations appear on the card and in the fees section. Final harness: 70 probes green, zero console errors on both pages.
State probe: window.__chiro exposes the active chip, its fee, the draw/settle flags and the animation token — QA gates on state, never on seconds.