PlumblineCeilings

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.

#F9F7F2 gyprock whitepage ground — a fresh sheet
#2B2925 shadow inkbody text, 13.4:1 on the ground
#3F58A7 chalk-line bluesnapped lines, links, CTAs
#A1762F plumb-bob brassgauge needle & marks only — never small text

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

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.

Verdict rules and worked figures (all measured from the running page)
ScenarioRule appliedBilledFigure
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 mmre-screw, area clamp binds11.2 → 12 m² min$456 + clamp note
Hall 5.0×1.2 m · any 10–40 mmre-screw, area clamp binds6.0 → 12 m² min$456
Living · 45 mmover 40 mm → replace $92/m²27.0 m²$2,484
Living · 15 mm + cracked togglecracking forces replace27.0 m²$2,484 + forced note
Any room · under 10 mm, no crackingmonitorprice-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

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

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); scrollWidth 375 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