01Concept
Sightline Optometry is the straight line from your eye to the thing you're looking at — the line the lens has one job to keep. The audience is anyone squinting at street signs, screen workers with 4pm headaches, over-45s whose arms got too short for the menu, and parents told the kid can't read the board. The art direction is the consult room at 10am: optical white daylight, graphite acetate frames, and the cobalt flash an anti-reflective coating throws when it catches the light.
The page performs its product. Everything outside the drifting lens circle wears your eye condition; everything inside it snaps sharp. That's the pitch, the demo and the reason to scroll to the booking form, in one element.
02Palette
The ink/line split from the collection's playbook: cobalt and tortoise draw marks; text sits in graphite or the derived tortoise ink. The dark price card inverts the scheme so the total reads like a phoropter's readout.
03Type
- Familjen Grotesk — display. A precise, round-cornered grotesque like a well-milled hinge; carries the masthead, headings and the street-sign lettering inside the SVG scene.
- Figtree — body and UI. Warm, legible workhorse at 16px+ on mobile.
- IBM Plex Mono — dioptres, prices, hours, the map's street labels. Every number on the page that claims to be honest is set in mono, so honesty has a typeface.
04The Sight Simulator
The scene is a single procedural SVG of Beaufort Street — federation parapets, striped awnings, the route 950 bus, the BEAUFORT ST blade sign — plus a near layer: a held phone with the deli menu open. No raster images anywhere; the "photography" is drawn.
The optics are two renders of the same artwork. The street (#farArt) and the phone (#nearArt) live in <defs> and are instanced twice with <use>: once as the uncorrected world, once clipped to a circle. The uncorrected copy carries an SVG filter chosen by the condition chips:
- Short-sighted — Gaussian blur on the distance layer only, σ = 1.3 × dioptres, so the stepper genuinely drives the rendering at every step.
- Long-sighted / reading age — the blur moves to the phone instead (σ = 1.15 × D); long-sighted adds a mild distance blur past +3.00, where accommodation honestly runs out.
- Astigmatism — a directional double-edge: small blur, then feOffset displaced along one axis and re-blended, with the offset scaled by the cyl value.
The clipped copy renders sharp — with one honest exception: single-vision lenses for a reading-age script soften the distance layer inside the lens, because reading glasses really do blur the street. The multifocal chip removes that softness; that difference IS the $200 the card asks for. The lens circle drifts on a slow Lissajous path (phased to rest on the street sign for the thumbnail), a trial-lens tick rim and a mono dioptre tag travel with it, blue-guard toggles an AR flash arc on the rim, photochromic tints the clipped area. Reduced motion parks the lens on the sign, settled and sharp.
The pricing model
| Anchor | Price | Behaviour in the simulator |
|---|---|---|
| Frame (acetate, fitted) | from $95 | Always on the card |
| Single-vision lenses / pair | $120 | Default lens chip |
| Multifocal lenses / pair | $320 | Replaces the SV line |
| High-index lens | +$90 | Auto-added past ±4.00 D, with the on-card reason |
| Blue-guard coating | +$60 | Toggle; also draws the AR flash on the rim |
| Photochromic | +$110 | Toggle; tints the corrected zone |
Measured from the running page: the rest state (short-sighted −2.50, single vision, blue-guard) reads $275 = $95 + $120 + $60. Stepped to −5.00 the card crosses the high-index threshold and reads $365 = $95 + $120 + $90 + $60. The cheapest possible output — coatings off, ≤ ±4.00 — is $215, which equals the services grid's "complete pairs from $215" floor exactly. All three figures match the spec's cross-derived arithmetic with no corrections.
Deliberate flatness, stated on-card: at or under ±4.00 the stepper changes the blur but not the bill — "single vision is one price band across everyday scripts — your strength changes the lens, not the bill." A control that visibly no-ops on price while honestly changing the rendering, per the collection's pricing-control rules.
05Conversion decisions
- The simulator shares the hero. At 1200×750 the scene, controls and the $275 card sit beside the h1 — the signature is inside the thumbnail viewport, not below it.
- Two CTAs above the fold — "Book an eye test" (anchor to the form) and the tel: link. On mobile a sticky bottom bar repeats both; tap targets ≥44px.
- Bulk-billing leads the page because it removes the biggest objection ("what does the test cost?") in the first sentence — hedged honestly, since some scans sit outside the Medicare schedule.
- Simulator→form handoff: condition, strength, lens and coatings pre-fill a read-only "from your Sight Simulator" line in the booking form, so the demo interaction arrives with the lead.
- Form fields — name, phone, suburb, last-test-when, preferred day (type=date, min today). "Last eye test" is the one field an optometrist actually triages on: five-plus years and never get the longer slot. Confirmation is local and says so plainly; nothing fakes a network round-trip.
06Local SEO we'd implement for the real business
This demo page ships only a WebPage schema naming it a demonstration — fictional structured data in a real index is dishonest markup. A real Sightline would ship LocalBusiness + Review schema like this:
{
"@context": "https://schema.org",
"@type": "Optician",
"name": "Sightline Optometry",
"description": "Independent optometrist in Mount Lawley. Bulk-billed
eye tests, complete glasses from $215.",
"url": "https://example.com.au",
"telephone": "+61 8 XXXX XXXX",
"address": {
"@type": "PostalAddress",
"streetAddress": "XXX Beaufort Street",
"addressLocality": "Mount Lawley",
"addressRegion": "WA", "postalCode": "6050", "addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -31.93, "longitude": 115.87 },
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Friday"],
"opens": "09:00", "closes": "17:30" },
{ "@type": "OpeningHoursSpecification",
"dayOfWeek": "Thursday", "opens": "09:00", "closes": "19:00" },
{ "@type": "OpeningHoursSpecification",
"dayOfWeek": "Saturday", "opens": "09:00", "closes": "13:00" }
],
"priceRange": "$$",
"aggregateRating": { "@type": "AggregateRating",
"ratingValue": "4.9", "reviewCount": "187" },
"review": [{
"@type": "Review",
"author": { "@type": "Person", "name": "Real Patient" },
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "Pulled from the practice's live review feed."
}]
}
Plus: Google Business Profile with the consult-room photos, suburb-level service pages only if the practice genuinely serves them, and FAQ schema on the six questions above — each answer already written the way a rich result wants it.
07What would change for the real client
- Practice management: Optomate or Sunix — appointments, clinical records and recalls; the booking form would write into its diary, not a mailbox.
- Claiming: Medicare Online for bulk-billed consults and Tyro/HICAPS terminal integration so health-fund gaps are quoted live, the way the trust strip promises.
- Bookings & recalls: HotDoc-style online booking with two-year recall reminders — recalls are an optometry practice's whole retention engine.
- Lens ordering: lab ordering feeds (Hoya/Essilor-style portals) driven by the same frame + lens + coating structure the simulator's card already uses.
- Back office: Xero for the ledger, Podium for the review flow that would replace the demo reviews with a live feed.
- Their frames photographed on their shelves, their real AHPRA numbers, their real fee schedule — the simulator's model is deliberately structured so a real price list drops straight in.
08Iteration log
PASS 1Craft
- Drove every control headlessly on a fresh load: rest card measured $275, ten stepper taps to −5.00 crossed to $365 with the high-index line and its reason on-card, coatings-off floor hit $215 — all equal to an independently reimplemented oracle. A boundary drive confirmed exactly ±4.00 stays a standard lens.
- The zero-console gate caught a real bug: the phone field's pattern="[0-9()+ ]" threw a v-flag SyntaxError — modern Chrome compiles pattern attributes as v-flag regexes, where unescaped parentheses are illegal in a character class. Escaped them; validation came back to life.
- Screenshot review at 1200×750: the lens rests sharp on BEAUFORT ST with the blurred street outside, and the hero h1, CTA and $-card all share the thumbnail viewport as composed. Tortoise amber measured ~4.1:1 as text, so all text-duty amber runs in the derived tortoise ink (#7A4C1D, ~6.7:1).
PASS 2Depth
- Scene-region screenshot review caught the astigmatism feBlend mode="multiply" darkening the whole street like storm light instead of doubling edges. Replaced it with a half-alpha feOffset ghost merged over the blur — the shop lettering now doubles in daylight, the way a cyl error actually smears.
- The second-read detail — single-vision readers soften the street inside the lens while sharpening the phone — measured too subtle at σ=1.6 to notice; raised to σ=2.2 and re-screenshotted until the softened WALCOTT ST read against the rest state. The on-card line now points at a difference you can see, which is the $200 multifocal argument made visually.
- Added the refocus micro-interaction: every state change pulses the trial-lens rim and pops the total — suppressed under reduced motion.
- Drove the full 4-condition × 2-lens × blue-guard matrix (16 states) plus photochromic against the oracle — every displayed card equal; chips also activate by keyboard focus.
PASS 3Hardening
- Masthead first at 375px: wordmark right edge 126px, tel icon at 172px, CTA at 221–353px — no collision, verified on the screenshot as well as by rect; the tel number text hides under 560px so the row never wraps. Both pages scrollWidth 375.
- Empty submit on a fresh load raised five validation states with visible messages and focus moved to the first; filled submit (ISO date via the generic driver) rendered the local confirmation with the simulator pick echoed and no faked network round-trip.
- Reduced-motion run: lens parked on the street sign at (663, 208), scene fully rendered and settled, zero console errors.
- Copy read caught an honest-numbers slip: the 20/20/20 answer said "20 metres" — the rule is 20 feet, corrected to six metres. Chanel rule: removed the second powerline. Final gate: 42/42 driven asserts, zero console errors across every run.