Industry demo · Tiling · Perth
How the Setwell Tiling demo was made
Setwell Tiling & Waterproofing is a fictional Myaree wall-and-floor tiler built to show a real one what their landing page could be: one page, one job — book the free measure — with an estimator that prices labour the way a tiler actually quotes it.
Concept
The audience is a renovator who has already picked the tile and now needs someone to lay it straight — plus the builder who needs a wet-area sub who turns up. The page owns the craft (the mid-job wall, the laser line, the membrane the tiles hide), not the lifestyle-bathroom gloss, and its single job is converting that trust into a booked measure. The signature is the Tile Estimator: a procedural SVG wall-and-floor cutaway that re-tiles itself live in the chosen format while an honest labour-only price card shows its working.
Conversion decisions
- Estimator beside the hero, not below it — it shares the first viewport (and the 1200×750 thumbnail) with the value proposition, because the working demo is the trust signal.
- Labour-only stated on the card, not in fine print. "You pick and buy the tiles" removes the price-anxiety a supply-and-lay figure creates, and it's how this trade actually works.
- Every control is honest or disabled with a reason: splashback greys the floor stepper ("splashbacks are wall work"), floors-only greys the wall stepper, alfresco greys waterproofing ("outdoor tiling wants falls and flexible grout, not a wet-area membrane"). No control silently no-ops.
- Estimator→form handoff: the scenario pre-fills the measure form's job type and description (until the visitor edits it themselves), so the demo interaction becomes a warmer lead.
- Form fields: name, phone, suburb — the minimum a tiler needs to call back — plus the pre-filled job description. Empty submit flags all three required fields; a valid submit renders a local confirmation that plainly says nothing was sent.
- Mobile-first: sticky call/measure bar (56px targets), full number in the header at desktop, a "Call" pill at 375px so the masthead never wraps.
Palette — wet-glaze morning
The spec's LINE/MARK accents held: cobalt draws the laser and the CTAs, aqua draws the membrane, and both were kept off body copy — the derived inks above carry all reading text at ≥4.5:1.
Type
Bricolage Grotesque (display) has chiselled terminals that read like a cut tile edge — set tight at −0.022em for the masthead moment, where "the laser line" carries a literal cobalt rule under the words. Mulish is the legible workhorse for body and UI. Martian Mono sets every m², joint and dollar figure, so the numbers read like a measured quote rather than marketing.
Techniques & the signature
Everything is procedural — no raster images. The cutaway is a single inline SVG: the wall is a flat elevation, the floor a skewed plane (matrix(1,0,0.45,1,…)) so a plain rect grid reads as perspective. On every input change the tile layer regenerates: the chosen format sets tile pitch and bond (600×600 grid, subway half-bond courses, fine mosaic, two-man 1200×600), courses fill bottom-up to a laser datum recomputed to keep the wall two-thirds tiled, and each tile is a rect that fades in on a per-index transition delay — a re-tiling animation with no keyframe conflicts, because tiles carry no SVG opacity attribute (position lives in attributes, animation lives entirely in CSS, per the collection's W16/W17 rule). A grout-coloured backing bed under the tiled zones makes the joints read at thumbnail size. Above the top course, generated arc paths draw the trowel's combed adhesive; the aqua membrane shows in the untiled shower zone and as the floor's cross-section edge. The laser line's glow pulses via CSS on an inner line (opacity floor 0.62 — never invisible at any capture instant), while its position is set as a transform attribute on the outer group. Second-read details: the laser emitter unit on the left wall edge, spacer crosses still sitting in the top course, and a movement joint across the floor plane that the grout-crack FAQ explains.
No canvas or WebGL is used, so no DPR/context handling was needed; reduced-motion renders every tile settled and the laser static. The page exposes window.__tiler (job, format, areas, membrane, rates, total, clamp and form status) so QA gates on state, not wall-clock.
The pricing model, honestly
Pinned anchors from the spec: floors $62/m², walls $85/m², mosaic +$30/m² and 1200×600 large format +$25/m² on either rate, waterproofing $55/m², strip-out $45/m², minimum call-out $450. The model's derived shape, documented so the numbers can be checked:
- Membrane area is derived, not dialled: for a full bathroom it is floor m² + a 4 m² shower-wall allowance (walls to 1.8 m around the shower — the assumption is stated on the card); for floors-only it equals the floor area (laundry/ensuite floors); splashbacks and alfresco have no membrane, each with its on-page reason.
- Format chips only modify the laying rates — subway and 600×600 lay at base rate; the surcharges are the two pinned ones.
- Strip-out is a toggle at the pinned $45/m² across whichever areas are live — off at rest so the rest-state card is pure laying + membrane.
- The clamp: any subtotal under $450 displays as $450 with the minimum-call-out line item and reason on the card, matching the services grid's "regrouts & repairs from $450" floor exactly.
Every figure below was measured from the running page and independently re-derived by a separate oracle implementation in the QA harness:
| Scenario | Working | Measured |
|---|---|---|
| Rest: full bathroom, 600×600, 22/5 m², membrane 9 m² | 22×85 + 5×62 + 9×55 | $2,675 |
| Same, 1200×600 large format | 22×110 + 5×87 + 9×55 | $3,350 |
| Splashback, mosaic, 6 m² wall | 6×(85+30) | $690 |
| Floors only, 1 m², no membrane | 62 → clamps to minimum | $450 |
| Rest + strip-out | 2,675 + 45×27 | $3,890 |
The spec's worked example ($2,675) matched the implemented model exactly — pure anchor arithmetic, no correction needed.
Local SEO we'd implement for the real business
The demo page itself carries only honest WebPage schema naming it a demonstration — fictional structured data in a real index would be dishonest markup. For a real tiler, we'd ship LocalBusiness and Review schema like this, fed by their actual details and review stream:
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"@id": "https://example-tiler.com.au/#business",
"name": "Real Tiling & Waterproofing Pty Ltd",
"description": "Wall and floor tiling and AS 3740 waterproofing
across Perth's southern suburbs.",
"telephone": "+61-8-XXXX-XXXX",
"address": {
"@type": "PostalAddress",
"addressLocality": "Myaree",
"addressRegion": "WA",
"postalCode": "6154",
"addressCountry": "AU"
},
"areaServed": ["Myaree","Melville","Applecross","Booragoon",
"Fremantle","Willetton"],
"openingHours": "Mo-Fr 06:30-16:00",
"priceRange": "$$",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9",
"reviewCount": "87"
},
"review": {
"@type": "Review",
"author": { "@type": "Person", "name": "Real Customer" },
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "Fed from the live review platform, never hand-written."
}
}
Plus suburb-level service pages, a Google Business Profile wired to the same NAP, and review markup fed from a live platform so the stars are earned, not asserted.
What would change for the real client
- Tradify — the measure form books straight into their quoting and job-scheduling pipeline, with the estimator's scenario attached as the job note.
- Xero — quotes convert to invoices with the waterproofing line itemised; progress claims for builder work.
- Supplier trade-account ordering — the estimator's areas become a take-off list (tiles +10% cutting margin, adhesive, membrane) pushed to the tile shop's trade account.
- Waterproofing-certificate PDF workflow — AS 3740 certificates generated per job, stored against the address, and attached to the invoice automatically.
- Podium — post-job review requests by SMS, feeding the reviews section and the schema above with real words.
- And their photos: the procedural cutaway stays as the estimator, but finished-job photography earns its place in a gallery the demo deliberately does without.
Iteration log
PASS 1 — CRAFT
Drove the whole surface headlessly (30 asserts): rest card measured $2,675 against the independent oracle, large-format $3,350, mosaic splashback $690, floors-only clamp $450 with the reason on-card, all three disable behaviours with reasons, empty submit flagging 3/3 required fields on a fresh load, filled submit confirming in the "thanks / received / we'd call" lexicon, FAQ, sticky bar, zero console errors. Screenshot review then caught what the asserts couldn't: tile joints didn't read — near-white tiles over a near-same-tone substrate, and the floor's grout gaps showed the aqua membrane through them, muddying the membrane story. Fixed with grout-coloured backing beds under both tiled zones. At 375px the masthead's "Free measure" pill wrapped to two lines; the full phone number now collapses to a "Call" pill under 620px and the row sits clean.
PASS 2 — DEPTH
Enriched the signature: a laser emitter unit on the left wall edge so the datum line reads as a tool, not decoration; a movement joint drawn across the floor plane that pays off the "why did my grout crack" FAQ (cross-surface consistency as a second-read detail); a price-total flash micro-interaction (colour ease, 0.7s) when the figure changes. Re-drove every scenario — including strip-out at $3,890 — against the oracle after the changes; full-page screenshot review of every section confirmed services, trust, reviews, map, FAQ and form all render as designed.
PASS 3 — HARDENING
Masthead first at 375px per the wave rule: one row, no wrap, all children inside the viewport box (screenshot verified, not just scrollWidth). Sticky bar fixed with 56px targets in the bottom edge; h1 + CTA + trust chips above the 667px fold; estimator bounding box top at 117px in the 1200×750 thumbnail viewport (asserted). Keyboard drive: Enter activates chips, toggles waterproofing and opens the FAQ. Reduced-motion load renders every tile settled at full opacity with the laser static. 768px and 1200px sanity clean, zero console errors throughout (the phone pattern was written for v-flag rules — escaped parens — and validates). Honesty sweeps: every phone number on the 9000 exchange, single WebPage JSON-LD block only, colophon exact. Chanel cut: removed the hero's aqua gradient wash, keeping only the faint tile-grid ghost. Final state: 34/34 asserts green.