Generative Assets · Wave 26 · Industry Demos XV
How Plumbline Ceilings was built
Site 289 in the collection — a conversion-first landing page for a fictional Perth ceiling repair business, designed & built by Sapience Analytics.
Concept
Plumbline Ceilings is a fictional Osborne Park ceiling repair specialist aimed at the Perth homeowner staring up at a bow, wondering whether the ceiling is about to come down. The page has one job: convert that worry into a free inspection booking — and one honest side-job: tell people with a widening bow or cracking sounds to get out of the room and call. The trade truth doing the work is real and local: 60s–90s gyprock went up on adhesive daubs, and forty summers of roof-space heat lets the glue go.
Palette
White-on-white craft — gyprock, shadow lines, cornice profiles — with the two tools of the trade as the only colour: chalk-line blue and plumb-bob brass. The most restrained site of the wave; the drama is a bowing ceiling drawn in section.
Per the collection's ink/line rule, brass never carries small text — the darker #7A5817 ink variant is used the one place a brass-family word (the REPLACE verdict) needs to be read.
Type
- Archivo, Expanded axis (wdth 125), 600–800 — headings, verdict words, prices. Wide, flat, architectural: the letterforms read like a shop-drawing title block, and the verdict word (MONITOR / RE-SCREW / REPLACE) set huge in Archivo Expanded caps behind the gauge is the page's typographic moment.
- Instrument Sans 400–700 — body, controls, forms. A quiet workhorse with just enough character in the terminals to not read as system UI.
The signature — the Sag Gauge
An SVG room cross-section with a taut string line (the straightedge every ceiling fixer actually uses) snapped across the ceiling. A sag stepper (0–60 mm) visibly bows the plasterboard sheet away from the string — the sheet's top and bottom edges are two quadratic Béziers whose control point sits at twice the sag depth, so the mid-span drop equals the dialled figure exactly (at an exaggerated vertical scale, declared on the drawing). Room presets (Bedroom 3.5×3.2 m, Hall 5.0×1.2 m, Living 6.0×4.5 m) re-scale the section and the priced area; a cracked/drummy toggle forces the replace verdict. Joists above the sheet stay put while the sheet drops away — the adhesive daubs visibly tear where the local gap opens, which is the actual failure being sold against. A brass-needle dial reads the sag against banded thresholds, and the verdict card states the rule it applied beside the price.
The whole scene is one inline SVG driven by attribute updates from a single render(sag, width) function — no libraries. Animation is a token-invalidated rAF tween: every control handler bumps the token and cancels the in-flight frame before swapping state, so rapid-fire preset/stepper/toggle sequences can never leave a stale closure animating dead geometry. First draw gets the full entrance (string line dash-draws in, hidden until its drawn length is > 0; the bow then eases in over 1.4 s); every subsequent change redraws in 420 ms. Reduced motion renders the settled frame immediately. State is exposed at window.__ceilings (room, sag, cracked, verdict, price, billedArea, settled, token) so QA gates on state, never on seconds.
Pricing rules & honest anchors
The verdict follows the spec's pinned rules, solved at the boundary — exactly 10 mm re-screws, exactly 40 mm still re-screws, 41 mm replaces, and cracking overrides everything. Under 10 mm is a designed price-less state: monitor — free 12-month re-inspection, no work sold today. Nothing is sold to a ceiling that doesn't need work; on a demo page that restraint is the sales argument.
| Scenario | Rule applied | Billed | Figure |
|---|---|---|---|
| Living 6.0×4.5 m · 22 mm (rest state) | 10–40 mm → re-screw $38/m² | 27.0 m² | $1,026 |
| Bedroom 3.5×3.2 m · 15 mm | re-screw, area clamp binds | 11.2 → 12 m² min | $456 + clamp note |
| Hall 5.0×1.2 m · any 10–40 mm | re-screw, area clamp binds | 6.0 → 12 m² min | $456 |
| Living · 45 mm | over 40 mm → replace $92/m² | 27.0 m² | $2,484 |
| Living · 15 mm + cracked toggle | cracking forces replace | 27.0 m² | $2,484 + forced note |
| Any room · under 10 mm, no cracking | monitor | — | price-less by design |
| Typical 4×2 full home (guide example) | replace $92/m² × pinned 140 m² | 140 m² | $12,880 |
The services grid floor — “re-screw & patch from $456” — equals the gauge's cheapest re-screw output (the 12 m² minimum × $38), so the page never argues with itself. Sub-metre areas are rounded to the whole dollar (Bedroom replace: 11.2 × $92 = $1,030.40 → $1,030); every displayed figure was cross-checked against an independently reimplemented oracle in the QA harness across all rooms × sags {0, 9, 10, 22, 40, 41, 45, 60} × cracked on/off.
Conversion decisions
- Gauge in the hero, not below it. The signature shares the first 750 px at 1200 wide with the value proposition — the visitor is playing with their own worry within one scroll-less glance, and the rest state (Living, 22 mm, RE-SCREW, $1,026) is a designed thumbnail, alive but held.
- Gauge → form handoff. Every gauge change pre-fills the enquiry's room select and description ("Living 6.0 × 4.5 m — about 22 mm of sag… est. $1,026"), so the demo interaction becomes a warmer lead. Typing in the description stops the prefill overwriting it.
- The safety band is conversion copy. "Keep everyone out of the room and call" is real advice stated plainly — it converts the scared visitor (who should call, not fill a form) and it's the honesty the whole page trades on.
- Form fields: name, phone, suburb, room, "what are you seeing?" — the minimum a scheduler needs to book an inspection window. Front-end validation with visible error states; the confirmation states plainly that a demo sends nothing.
- Mobile: sticky call/book bar, ≥44 px tap targets, the masthead collapses to wordmark + call chip at 375.
Local SEO we'd implement for the real business
The live page ships only WebPage/CreativeWork schema naming it a demonstration — fictional business data in a real search index would be dishonest markup. For a real client we'd ship LocalBusiness + Review structured data like this:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HomeAndConstructionBusiness",
"name": "Plumbline Ceilings",
"description": "Sagging ceiling repair and replacement across Perth.",
"telephone": "+61-8-9000-0289",
"address": {
"@type": "PostalAddress",
"addressLocality": "Osborne Park",
"addressRegion": "WA",
"postalCode": "6017",
"addressCountry": "AU"
},
"areaServed": "Perth Metropolitan Area",
"openingHours": ["Mo-Fr 07:00-17:00", "Sa 08:00-12:00"],
"priceRange": "$$",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9",
"reviewCount": "187"
},
"review": {
"@type": "Review",
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"author": { "@type": "Person", "name": "A real customer" },
"reviewBody": "Measured the sag, re-screwed in a day…"
}
}
</script>
Plus: suburb-level service pages for the highest-volume search corridors ("ceiling repairs Joondalup"), Google Business Profile with before/after photo streams, and review schema fed from the live Google reviews — never hand-typed.
What changes for the real client
- Their photos where the procedural art sits — real roof-space fixings, real flushed finishes (the SVG section stays as the explainer diagram; it earns its place).
- Live Google reviews replacing the demo quotes.
- The enquiry form posting to their job-management system — ServiceM8, Tradify or AroFlo are the usual suspects for WA ceiling fixers — with the gauge's scenario attached to the job record, so the estimator arrives knowing the room and the sag.
- A real booking calendar on the make-safe line, and insurer-ready inspection report PDFs generated from the same measurements the gauge demonstrates.
Iteration log
Pass 1 — Craft
- The desktop hero h1 stacked six lines tall with "AND" stranded alone — the screenshot caught what no assert models. Cap dropped from 3.15 rem to 2.8 rem; it now sets in four balanced lines beside the gauge.
- The SVG fine-print token (#9C968A) measured under 4.5:1 on the scene ground — demoted to the body ink-muted #6C665A (the collection's ink/line split applied to its own drawing notes).
- Dimension-marker arrows collapsed into each other below ~8 mm of drawn sag — the marker now flips to an outside-arrow layout under 14 px of gap, and hides entirely under 1.5 mm rather than drawing a zero-height measurement.
- The verdict ghost word was sized for the Living span and spilled past the Bedroom preset's walls — ghost type now steps 62→54→44 px with the room.
- Full driven sweep: hard-reload empty submit (validation up), filled submit (confirmation), all rooms × sags {0, 9, 10, 22, 40, 41, 45, 60} × cracked on/off against the oracle — 296 asserts green.
Pass 2 — Depth
- Second-read detail: the adhesive daubs under each joist tear in two — one remnant on the joist, one riding down on the sheet — wherever the local gap opens past 3 px. The failure mechanism the copy describes is drawn, not narrated. Re-screw verdicts scatter screw dots along the bowed sheet at every joist line: the fix, previewed.
- Micro-interaction: the verdict price pops in with a 280 ms rise whenever the figure changes (stilled under reduced motion).
- Driven-state screenshots caught two collisions the asserts sailed past: the "cracking / drummy" caption overprinted the room label (label moved to sit above the floor line), and the dial's 0/60 numerals crowded the mm readout (removed — the 20/40 numerals and threshold ticks carry the scale).
- Rapid-fire drive — preset, three stepper clicks, toggle, two more presets, two steps, toggle again, all dispatched in one evaluate with no settle between — token invalidation held: the settled frame matched the final state and the oracle, zero console errors.
Pass 3 — Hardening
- 375 px masthead first: wordmark and call chip clear each other (the header CTA folds into the sticky bar);
scrollWidth375 on both pages; guide tables scroll inside.table-scroll. - Reduced-motion path renders the settled rest frame immediately (
settled:true, $1,026 and the 22 mm bow visible, pulses stilled). Tab-hidden mid-tween jumps to the settled frame on return. - The 1200×750 thumbnail crop initially cut the price off at the fold — the verdict card was restructured so the verdict word and the dollar figure share the top row (better hierarchy anyway), the section's viewBox tightened and control padding trimmed, and a hard assert added: the rest-state $1,026 must sit fully inside the first 750 px. It does.
- Signature bounding box confirmed intersecting the first 750 px at 1200 wide; sticky call bar's tel link within the bottom 140 px at 375.
- Chanel rule: removed the map's north-arrow ornament — the coastline and river already orient it.
- Phone pattern re-checked against v-flag regex rules in the harness; zero console errors across hard reloads, the full drive matrix, and both pages.
Techniques
- Inline SVG cross-section with attribute-driven geometry — no canvas, no libraries, ~9 KB of scene code.
- Token-invalidated rAF tweens with dual-speed redraw (entrance vs. subsequent) and a
visibilitychangejump-to-settled path. - Quadratic-Bézier sheet bow with per-joist gap sampling (
4·s·t·(1−t)) driving the torn-daub detail. - Procedural SVG metro map; CSS-only entrance choreography that never strands content at opacity 0.
- All interactive state mirrored to
window.__ceilings; every figure asserted against an independent oracle.