Generative Assets · Industry Demos XXV · site 336
Trowel & Float Rendering — how it was made
A conversion-first landing page for a fictional Balcatta rendering business, built as the pattern Sapience Analytics would ship for a real Perth renderer: price the elevation on the page, then book the site measure.
Concept
Trowel & Float Rendering does cement render, acrylic texture systems and bag-and-paint on Perth's 1980s–2000s face-brick homes. The audience is the owner about to sell (or stay) who wants the "rendered look", the builder's client choosing a texture system, and anyone whose old render is cracking. The page has one job: a site-measure booking with the elevation, finish and area already priced — so the first phone call is about dates, not "how much".
Art direction is a rendering site at 10am: limewash-white ground, Colorbond-monument ink, trowel-steel blue for the actions, sand-render linework. The whole page reads like a wall half-done — one side brick, one side smooth.
Palette — measured, not assumed
The spec's contrast figures were hypotheses; every one was measured with WCAG relative-luminance arithmetic from the shipped hex values in Pass 1. Trowel steel cleared 4.5:1 on the ground (4.86:1), so it stays for links and button fills — but all small accent-coloured copy (chip prices, service prices, addon reasons) uses the pre-minted steel ink at 8:1, the ink/line token split. Sand render never carries text; sand ink does. Secondary body copy uses #4A4F57 at 7.24:1.
Type
Archivo Black (400) for the wordmark, headings, the display line and the money — a signwriter's grotesque with the weight of a trowel; the same face a real-estate board or a ute door would carry. Public Sans for everything else: a workhorse that stays legible at 13px inside the ledger and on the drawn board. Body is 17px on mobile. The typographic moment is the display line above the elevation — "ONE-EIGHTY SQUARE METRES, FLOATED SMOOTH" — set in caps at up to 34px, where the number is written in words from the live area (twenty … one-eighty … four hundred) and the second half follows the finish (floated smooth / texture-coated / bagged and painted).
The signature — the Render Elevation
A drawn SVG street elevation of a brick home, built from JavaScript on every state change so the scope chips genuinely redraw the house rather than toggling layers. The face brick is a 30×14 <pattern> of sand-render coursing over a warm clay fill. The rendered state is a second wall layer — flat fill plus a finish texture pattern (fine sand speckle for cement, a two-tone stipple for acrylic, a rotated wavy-line hessian drag for bag-and-paint) — clipped by a four-point <clipPath> polygon whose right edge is the trowel line, leaning 9 units so it reads as a wet edge, with a 52-unit gradient darkening behind the blade.
The trowel rides that edge on a requestAnimationFrame loop: edgeFrac = 0.45 + 0.13·sin(0.85t), so the rendered region always covers between 32% and 58% of the wall — the never-invisible floor is coverage rather than opacity: at any capture instant the wall is visibly half brick, half render, at full opacity. The blade tilts ±7° with the direction of travel. The delta is clamped both ways (dt = min(max(now − last, 0)/1000, 0.05)), the loop pauses on document.hidden, and reduced-motion skips the loop and paints the 0.45 frame once.
Scope chips redraw the geometry: front elevation ghosts the side return wing (dashed, 38% opacity — "not in scope"), single-storey draws it solid, double-storey lifts the eave, adds three upper windows, a floor course and a drawn scaffold (five standards, two lifts of planks with guard rails). Finish chips swap the fill and texture; the paint topcoat swaps raw grey cement for a painted off-white. Reveals & quoins draws alternating quoin blocks at both corners and 8-unit reveal frames around every opening — inside the clipped render layer, so they appear only where the trowel has been. The estimate board is drawn on the wall like a real-estate board (monument plate, light-steel screws): "SITE ESTIMATE / $13,140 / cement render · 180 m² + topcoat". Below 600px the board ships a tight variant (170×66, total only at 40 units) so it never covers the drawn windows at 375.
Every control handler bumps a token before touching state; the rebuild is synchronous and the loop reads scene references refreshed by each render, so a rapid-fire chip sequence never leaves a stale closure alive. First draw staggers the drawn groups at 90 ms (1.3 s cap); every later redraw runs at 26 ms (460 ms cap) via a firstDraw flag. window.__renderer exposes scope, finish, area, billed area, toggle states, lock flags, ledger lines, total, badge text, edge fraction, frame count and a settled flag.
Pricing model — pinned anchors, measured outputs
| Line | Rate | Rule |
|---|---|---|
| Cement render, sand finish | $55/m² | Supply and apply per m² of wall, GST included |
| Acrylic texture system | $85/m² | Base coat + texture, colour through |
| Bag-and-paint | $48/m² | Bagged finish + two coats exterior paint, included |
| Area stepper | 20–400 m² ×10 | Scope chips SET it (front 60 · single 180 · double 320); it stays live afterwards and never changes the scope chip |
| Minimum | 40 m² | Billed at the selected finish; multiplies the topcoat line too. 30 m² → note "billed at the 40 m² minimum"; 40 m² → no note |
| Paint topcoat | +$18/m² × billed | Live on cement only. Disabled on acrylic: "the texture coat IS the finish — no paint needed". Disabled on bag-and-paint: "bag-and-paint already includes two coats". The owner's choice is remembered and restored when cement is re-selected |
| Reveals & quoins | +$450 flat | Live at every scope × finish |
| Scaffold | +$1,200 flat | Forced ON and locked for double-storey ("two storeys need a scaffold — WorkSafe's rule and our knees'"); OFF and disabled for front and single ("ground-level work runs off trestles"). Scope fully owns it — nothing to restore |
| Crack repair & re-coats | no number | "Quoted on inspection" — a designed price-less line in the grid and under the ledger, never in the estimate |
Toggle matrix
| Toggle | Front · cement | Front · acrylic | Front · bag | Single (same as front) | Double · cement | Double · acrylic | Double · bag |
|---|---|---|---|---|---|---|---|
| Paint topcoat | live | disabled | disabled | live / disabled / disabled | live | disabled | disabled |
| Reveals & quoins | live | live | live | live | live | live | live |
| Scaffold | off, disabled | off, disabled | off, disabled | off, disabled | locked ON | locked ON | locked ON |
Worked examples — all measured from the running page and cross-checked against an independent oracle
| Scenario | Arithmetic | Measured |
|---|---|---|
| Rest: single, 180 m², cement, topcoat ON, reveals OFF | 180×55 + 180×18 | $13,140 |
| Front, 60 m², acrylic, no toggles (topcoat disabled) | 60×85 | $5,100 |
| Double, 320 m², acrylic, reveals ON, scaffold forced | 27,200 + 450 + 1,200 | $28,850 |
| Single, 180 m², bag-and-paint (topcoat disabled) | 180×48 | $8,640 |
| Bag-and-paint, stepper 30 m² → billed 40, note shown | 40×48 | $1,920 |
| Bag-and-paint, 40 m², no note | 40×48 | $1,920 |
| Cement, 20 m² + topcoat → billed 40 on both lines | 40×55 + 40×18 | $2,920 |
| Grid floors: bag $1,920 · cement $2,200 · acrylic $3,400 | 40 × rate | match |
Zero spec corrections: every pinned figure landed exactly. Totals are integer by construction (integer rates × integer areas ×10, flat add-ons), so no rounding rule was needed.
Conversion decisions
- Above the fold at 375: wordmark, the eyebrow trust line (Balcatta · Est. 2011 · registered building contractor), the h1 naming trade and area, and the steel "Book a site measure" button — all inside the first 740px, CTA bottom measured at 466px.
- Two ways to act, always: click-to-call in the header (number hidden below 560px, the button stays), the ghost call button in the hero, and the fixed mobile bar with call + book. Trades traffic is a phone in one hand.
- The estimator sits beside the hero, not below it: the elevation and its board are inside the 1200×750 thumbnail; the chips, stepper and ledger follow immediately, with the ledger sticky on desktop so the number stays in view while you change scope.
- The estimate hands off to the form: the scope textarea and the storeys select pre-fill from the live state (scope · finish · area · toggles · total) until the visitor edits them, so the enquiry arrives warm.
- Form fields are what a renderer actually needs: name, phone (v-flag-safe pattern), suburb, storeys, scope. Front-end validation with visible focus rings; the confirmation panel is hidden on load and on an empty submit and appears only after a valid filled submit — no fake network round-trip, and it says so.
- Honest lines wherever the total appears: the minimum note prints in the ledger and under the stepper; the crack-repair "quoted on inspection" line sits under the ledger total and in the services grid.
Local SEO we'd implement for the real business
The live page carries only WebPage, WebSite, CreativeWork and a BreadcrumbList — a fictional business must not put business-shaped structured data into a real index. For the real client we would ship HomeAndConstructionBusiness (the schema.org organisation subtype for building trades — more precise than bare LocalBusiness, and rendering has no narrower type of its own), with the real ABN, address, hours, service area and a live review feed:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HomeAndConstructionBusiness",
"name": "Trowel & Float Rendering",
"url": "https://example.com.au/",
"telephone": "+61 8 9000 0336",
"address": { "@type": "PostalAddress", "addressLocality": "Balcatta", "addressRegion": "WA", "postalCode": "6021", "addressCountry": "AU" },
"areaServed": ["Balcatta", "Karrinyup", "Dianella", "Morley", "Joondalup", "Wanneroo", "Perth"],
"openingHoursSpecification": [{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"], "opens": "07:00", "closes": "16:00" }],
"priceRange": "$$",
"hasOfferCatalog": { "@type": "OfferCatalog", "name": "Rendering services", "itemListElement": [
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Cement render, sand finish" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Acrylic texture systems" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Bag-and-paint" } }
]},
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "63" },
"review": [{
"@type": "Review",
"author": { "@type": "Person", "name": "Real customer name" },
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "Pulled from the Google Business Profile feed, never hand-typed."
}]
}
</script>
Plus: a Google Business Profile with the service area set to the metro, suburb landing sections for the brick belt (Karrinyup, Dianella, Morley, Joondalup), before/after galleries with the suburb in the alt text, and the FAQ marked up as FAQPage once the answers are the client's own.
What would change for the real client
- Their walls, not ours: the drawn elevation stays as the estimator, but the reviews, the trust strip and the hero gain their real photos, real Google reviews and their real licence, insurance and warranty terms.
- Job management: the site-measure form posts straight into Tradify or ServiceM8 as a new enquiry with the estimator scope in the job notes, so the office books the measure from the job board instead of retyping.
- Quoting and invoicing: the site-measure quote is issued from the same system and syncs to Xero; the deposit invoice on acceptance and the final on completion follow without a spreadsheet.
- Their real numbers: the per-metre rates, minimum, add-ons and scope presets are a nine-line config the client can change without a developer.
- Colour: the finish chips would carry the client's real texture-system colour range so the elevation previews the actual palette they apply.
Iteration log
Pass 1 — Craft
- Measured every palette pair; trowel steel cleared 4.5:1 for links (4.86:1) so no button remedy was needed, but every small accent copy token was moved to steel ink (8.00:1) and sand-coloured copy to sand ink (5.45:1). Figures recorded above.
- First screenshot showed the rendered half of the wall almost indistinguishable from the brick half — the brick face fill (
#ECE7DC) sat too close to the painted render. Warmed the brick to a pale clay#E4D6C3; the half-brick/half-smooth argument now reads at a glance. - The wall-area block was crushed into a half-column and its label wrapped to five lines; widened area and extras blocks to the full control width.
- Service-area map: "Balcatta — base" collided with Dianella and Joondalup ran into Wanneroo; moved the labels, cropped 70 units of empty ocean off the top.
- Copy read: FAQ answers tightened, "quoted on inspection" wording made identical in the grid and under the ledger.
Pass 2 — Depth
- Found the trowel disappearing for a third of every loop: it swept behind the estimate board (drawn later in z-order). Rather than paint the trowel over the board, the sweep band was narrowed to 32–58% of the wall so the blade always stops short of the board — and the board sits on the still-brick side, which reads better anyway.
- Moved the door to the left bay and dropped the trowel into the strip under the sills, so the blade floats over wall, not glass; the double-storey trowel works the upper floor from the scaffold.
- Second-read detail: quoins and reveals are drawn inside the clipped render layer, so toggling them shows them appearing only where the trowel has already been.
- Wet-edge gradient behind the blade; ±7° blade tilt with direction; front-elevation scope ghosts the side wing with a dashed outline; scaffold gained plank boards, guard rails and base plates.
- Ledger made sticky on desktop; hover states on chips and steppers.
Pass 3 — Hardening
- 375 masthead checked first: wordmark right edge 153px vs call button left edge 268px, no collision; scrollWidth 375 on both pages.
- Native-resolution label-collision sweep at 375 and 1200 caught two: the top scaffold plank striking through the upper window labels and the first plank clipping BED 1/BED 2. Lifts moved to G−200 and eave+16; re-shot clean.
- Badge tight variant checked at native 375: 170×66 board, total only, clear of the windows and door.
- Reduced motion: no rAF loop, all drawn groups at opacity 1, settled flag true, rest total intact.
- Rapid-fire drive (twelve control clicks in one evaluate) ends on the asserted double/bag-and-paint/320 m² state with no console errors; every worked example, both minimum boundaries, both topcoat-disabled reasons and the scaffold lock asserted against the oracle.
- Chanel rule: removed the scaffold's diagonal braces (they struck through labels and added nothing).
Rest-state price measured from the running page: $13,140 (single-storey full exterior, 180 m² cement render with paint topcoat). Zero console errors, one <h1> per page, live JSON-LD limited to WebPage / WebSite / CreativeWork / BreadcrumbList / ListItem.