Generative Assets · Industry demo 272 · build guide

How Steamline Carpet Care was made

Steamline Carpet Care is a fictional Morley carpet steam cleaning operator — a single conversion-focused landing page showing what Sapience Analytics would build for a real cleaning business. The page has one job: turn "how much for my rooms?" into a booked clean, and the Room Planner answers that question before the visitor has to call.

Palette — fresh-steam morning, jade on mist

Every colour is argued from the job: a Morley loungeroom at 9am, windows open while the carpet dries.

#EEF3F2 morning mistground — cool drying-room light
#33403E wet slatestructure & primary ink — damp pile in shadow
#178F6B steam jadeLINE/MARK only — wand lanes, gauges, rules
#12805F jade-deepderived — buttons & jade text, 4.9:1 on white
#C4761F citruspre-spray bottle — chips, focus rings, pet dots
#8A5112 citrus-inkderived — citrus as text, 5.7:1 on mist

The spec's ink/line rule applied twice: steam jade fails 4.5:1 as small text, so buttons and jade copy use a derived #12805F; citrus fails as link text, so links use a derived #8A5112. The bright tokens are reserved for lanes, marks and chip borders — exactly the duties where contrast rules don't bite.

Type

The signature — Room Planner

A procedural SVG top-down house plan that cleans itself live. Bedrooms and living areas tile into the plan as the steppers climb; each room is striped with alternating wand lanes. The flagship living room rests mid-pass: grey scruffy lanes on the uncleaned side, bright jade on the cleaned side, and the wand itself is the divider. The implementation is a full-lane grey layer with a jade lane layer above it clipped by a <clipPath> rect — one rAF loop eases the clip width and the wand's transform attribute between 35% and 72% of the room on a 14-second ping-pong, so the cleaned fraction never drops below the 0.35 visibility floor and the thumbnail reads mid-demonstration at any capture instant. Reduced motion renders the wand settled at 55% with the steam stilled. Position lives on outer <g transform> attributes and entrance animation on inner groups' CSS only, so attribute state never fights a stylesheet rule (the W16/W17 lesson). Redraws are dual-speed: the first render staggers rooms in at 60 ms/element (capped 1.4 s), every later stepper tap redraws at 12 ms/element under a ~520 ms cap.

Second-read details: the truck-mount hose threads in through the front door and re-routes to the wand every frame, and three steam wisps rise off the wand head on a 2.4-second cycle. Pet-treated rooms take a citrus dot; stairs dock as an annex on the plan's right edge; rugs park on the flagship floor with fringed ends.

The pricing model — shape and measured figures

Truck-mounted hot water extraction, pre-spray and deodorise included. The model is deliberately flat where the spec pins it flat: one honest room rate — living areas meter at the same $45 as bedrooms ("a room is a room — the size band is the meter, not the label"), stated on-card rather than inventing a gradient. A room is a room up to ~14 m² (the $/room anchor's fixed dimension, declared on-card); rugs are $45 up to ~2×3 m, larger quoted at the door.

AnchorRateNote
Carpeted room (bed or living)$45 / roomup to ~14 m²; open-plan counts as two
Minimum job$991–2 rooms clamp up; crossing clears at 3 rooms
Hallway+$25threads the plan when chipped
Stairs$75 / flighthand-wand work
Rugs$45 eachup to ~2×3 m
Pet urine treatment+$30 / room affectedenzyme; affected count clamped to rooms selected
Upholstery$50 / seat · $150 minown service card, outside the planner

Measured from the running page (harness asserts against an independently reimplemented oracle, per LEARNINGS W14):

ScenarioArithmeticDisplayed
Rest — 3 bed + 1 living + hallway4 × $45 + $25$205 ✓
Rest + pet treatment on 2 rooms$205 + 2 × $30$265 ✓
Cheapest — 1 room, no add-ons$45 → min clamp$99 ✓ (equals services floor)
Three-room crossing3 × $45$135 ✓ (clamp released)
3 rooms + 2 flights + 1 rug$135 + $150 + $45$330 ✓

No spec corrections were needed — every worked example was pure anchor arithmetic and the implemented model landed exactly on it. The clamp prints its reason on the card ("the truck-mount heats up and the hoses run in whether we clean one room or four"), and the planner blocks the dishonest zero-room state: the last room's minus button disables rather than letting the card price an empty house.

Conversion decisions

Local SEO we'd implement for the real business

This demo page ships only WebPage schema naming it a demonstration — fictional structured data in a real index would be dishonest markup. For a real client, we'd ship LocalBusiness + Review schema like this:

{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "name": "Steamline Carpet Care",
  "description": "Truck-mounted carpet steam cleaning across Morley and the Perth metro.",
  "telephone": "+61 8 9000 0272",
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Morley",
    "addressRegion": "WA",
    "postalCode": "6062",
    "addressCountry": "AU"
  },
  "areaServed": ["Morley", "Dianella", "Bayswater", "Noranda", "Perth"],
  "openingHours": ["Mo-Fr 07:00-17:00", "Sa 08:00-15:00"],
  "priceRange": "$99-$500",
  "review": {
    "@type": "Review",
    "reviewRating": { "@type": "Rating", "ratingValue": "5" },
    "author": { "@type": "Person", "name": "— real customer, via review feed" },
    "reviewBody": "— pulled live from Google reviews, never hand-typed"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.9",
    "reviewCount": "— live count from the review platform"
  }
}

Plus suburb-level service pages, Google Business Profile sync, and review markup fed from the live platform rather than pasted.

What would change for the real client

Iteration log

Pass 1 Craft

Drove the whole conversion surface headless (25 asserts): rest card $205 = oracle, pet scenario $265, one-room clamp $99 with the reason row visible, three-room crossing $135 with the clamp released, stairs+rugs scenario $330; empty submit on a fresh load raised 3 validation signals, filled submit rendered the confirmation with the scenario sum; FAQ ×6 toggled; wand drift confirmed via the state probe (wandT 0.58→0.69) with the 0.35 floor held. The screenshot review caught what the asserts couldn't: room labels sat illegibly on the lane stripes (gave every label a white pill), and the "hose in through the front door" caption collided with the hose path at bottom-left (moved to bottom-right, end-anchored). Also fixed the mobile call button to a true 44px target with a "Call" short label.

Pass 2 Depth

Enriched the signature: three steam wisps now rise off the wand head (sine-drift, 2.4 s cycle, opacity fading with height — kept inside the wand group so attribute state never fights CSS), and the price total pops 7% on a spring bezier when the figure changes. Verified the dual-speed redraw honestly: a stepper tap after first render settles every room inside 620 ms. Screenshot review of the pet scenario: label pills legible, citrus dots on the two affected bedrooms, card itemising 4 × $45 + $25 + 2 × $30 = $265 — matches the oracle.

Pass 3 Hardening

375px masthead first (the W18/W21 offender): wordmark right edge 232px vs call button left edge 267px — clear by 35px, button 44px tall, no overflow (scrollWidth 375). H1, call CTA and trust line all above the 812px fold; sticky bar fixed at the bottom with the tel link, and its quote button scrolls to the form. Keyboard path drove the hallway chip with Space. Reduced-motion run: wand settled at 0.55, hero visible, zero console errors. Reserved-phone positive sweep: every (08) number on the page uses the 9000 exchange. One screenshot appeared to show an empty plan — chased it and found the snappy redraw caught ~150 ms mid-entrance, not a defect; a settled stage screenshot shows all rooms at opacity 1. Chanel rule: removed the second (citrus) hero radial gradient — the jade one carries the corner alone.

Techniques