Generative Assets · Wave 39 · Industry Demos XXVIII · site 353
How the Dryland Water Cartage demo was built
A fictional Byford water carter, built as a single conversion landing page to show a real operator what their site could be — one signature (the Tank Fill), one honest pricing model, and every pixel procedural.
Concept
Dryland Water Cartage delivers potable and non-potable water — tank top-ups, pool fills, dust suppression, stock water — from a depot on the Byford flats across the Perth hills, Peel and the outer south-east metro. The customer is the semi-rural family whose tank ran dry, the new pool owner, the site supervisor with a Monday start, the hobby farmer with troughs. The page has one job: a delivery request with the purpose, water, truck, load, zone and extras already priced. The Tank Fill draws the truck reversed up to the destination, fills it, and prints the delivered price on a docket clipboard on the truck door.
Palette — measured, not assumed
Argued from a sun-bleached poly tank, black tyres, a hi-vis vest and the blue of tank water. Every ratio below was measured from the shipped hexes with WCAG arithmetic in the Pass 1 harness, not carried from the spec.
Bleached grey · #E9E8E3Page ground — the poly tank after ten summers.
Tyre black · #23282CBody ink. 12.13:1 on the ground; 10.93:1 on the deeper booking ground.
Hi-vis orange · #E8891FCTA fill with tyre-black labels — 5.69:1. Never used for text on the ground (2.1:1).
Hover fill · #DA8020Spec's #D0771A measured 4.49:1 under dark labels; re-minted one step lighter to 5.02:1.
Orange text-ink · #8A4A08For orange-coloured copy: 5.59:1 on the ground, 6.38:1 on cards, 6.56:1 on the docket paper.
Tank blue · #3B8FB4Water, hose, gauge marks, chip outlines — lines and marks only (3.0:1).
Blue text-ink · #1F5F7ABlue copy, links, eyebrows: 5.75:1 on the ground, 6.57:1 on cards, 5.79:1 on the blue tint.
Soft ink · #4B535ASecondary copy: 6.38:1 on the ground, 5.74:1 on the deeper booking ground.
Type
Big Shoulders Display 700/800 for display — a truck-door condensed with a friendly counter, set in caps for the h1, section heads, the docket price and the load line ("FIFTEEN THOUSAND LITRES, DRINKING WATER, TODAY", which rewrites itself from the state: the kL in words, the water, and "this morning" when urgent is on). Public Sans for everything else, 17px body, 16px minimum on mobile inputs. Numbers in the ledger and tags are Public Sans 600 so they read as figures, not decoration.
Techniques
- Everything is inline SVG built with
createElementNS at render time — no raster anywhere, no libraries beyond Google Fonts.
- The service-area map is hand-drawn SVG paths (coast, escarpment, three zone bands, highway) with a dot-pattern fill.
- Entrance: a
.rise stagger gated on document.fonts.ready with a 1.2 s fallback and a no-js guard so nothing sits at opacity 0 without JS.
- Reduced motion: CSS media query kills the beacon flash and the entrance; JS reads
matchMedia and skips the rAF loop entirely, painting the settled level once.
- rAF loop with the delta clamped at zero and capped at 50 ms; work skipped while
document.hidden.
Signature implementation — the Tank Fill
One 900×560 SVG scene rebuilt from state on every change: horizon by zone (Byford flats scrub, escarpment and jarrah, or a subdivision roofline with power poles), a gravel pad, the truck (a bonneted 10 kL rigid with two axles, the longer 15 kL rigid with a tri-axle, or a prime mover and tanker for the 30 kL semi), the destination by purpose (poly rainwater tank, backyard pool with fence and ladder, site water cart with spray bar and site sign, or a stock trough under a header tank), a hose from the truck's rear outlet to the destination's inlet, and a tag pair — the kL tag with a leader to the inlet and a trip counter of small truck silhouettes capped at six drawn (the tag prints the true count, "+3" beside the row at nine). The water level is a clipped rect plus a sine-sloshed surface path filled to kL ÷ drawn capacity (tank and pool 90 kL, cart and trough 30 kL, clamped at full — the a11y mirror prints the percentage and the true kL). Dual-speed redraw: the first render rises the level over 2.4 s with a 90 ms element stagger; every later change redraws in 520 ms with a 30 ms stagger. Every handler bumps the token before it swaps state, and the loop reads a single anim object replaced atomically by render(), so a rapid-fire burst can never index a stale scene. The docket clipboard is an HTML overlay anchored to the bottom-left of the stage over the cab door at ≥1100 px and 641–959 px; below 640 px and between 960–1100 px it lies in flow on the pad under the drawn scene, so it never covers the barrel, placard, tank or tags. Urgent draws a flashing beacon (CSS on a nested element with no opacity attribute) and a SAME DAY clock tag; long hose draws a coiled hose on the pad; the water chip swaps the stream colour and the barrel placard between DRINKING WATER and NOT FOR DRINKING. Second read: the 6 am sun climbs about a pixel every two seconds the longer the page is open.
Pricing model (pinned anchors)
GST-inclusive. Delivered price = water × kL + delivery × trips (+ urgent × trips, + hose flat). Trips = ⌈kL ÷ truck⌉. Water multiplies the actual kL, never the truck capacity; the last trip is a part-load. All figures are integer by construction (whole-dollar rates × integer kL and trips).
Worked examples — measured from the running page against an independent oracle
The harness reimplements the model in separate code, sets the full control vector for every scenario (never inheriting load state) and reads the probe, the docket, the ledger and the mirror. Every figure below is the spec's pure-anchor arithmetic and every one measured identically — no corrections.
Cheapest output ($150 — 5 kL non-potable on the 10 kL rigid, local) equals the services grid's "from $150 a delivery" floor; potable $9/kL, non-potable $6/kL and "delivery from $120 a trip" match the grid word for word.
Conversion decisions
- Above the fold at 375: name, the value proposition naming the trade and the area, "Book a delivery" and the call button, the WC 0000 licence chip and a "Tank dry? call before 10am" line — the same-day promise is the strongest reason a rural customer rings a carter, so it sits in the hero and again in the sticky bar.
- Sticky bar on mobile with the same-day line above two buttons: call (hi-vis) and book (blue tint).
- Form fields: name, mobile, suburb or locality (rural addresses are localities, not suburbs), when (tomorrow / this week / later / standing run), an access-notes textarea (gate, track, where the tank sits — the thing that saves a wasted trip), and the pre-filled delivery textarea from the Tank Fill. Front-end validation only; a designed confirmation panel hidden until a valid submit; nothing pretends to send.
- Docket on the door: the price lives inside the artwork so the 1200×750 thumbnail carries the commercial argument; the ledger below itemises it and the mirror repeats it in words.
- Honest floors: every control changes the price or visibly says why it can't (the water lock under dust suppression); price-less lines say "quoted".
Local SEO we'd implement for the real business
The demo page carries only WebPage / WebSite / BreadcrumbList schema naming it a demonstration. For a real operator we'd ship this — schema.org has no water-cartage subtype, so the top-level type is plain LocalBusiness with the service catalogue carried in hasOfferCatalog. Reviews would come from the operator's real customers via their review feed, never typed in.
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Dryland Water Cartage",
"image": "https://example.com.au/photos/15kl-rigid-at-tank.jpg",
"url": "https://example.com.au/",
"telephone": "+61 8 9000 0353",
"priceRange": "$$",
"address": {
"@type": "PostalAddress",
"addressLocality": "Byford",
"addressRegion": "WA",
"postalCode": "6122",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -32.22, "longitude": 115.99 },
"areaServed": ["Byford", "Serpentine", "Mundijong", "Jarrahdale", "Roleystone", "Karragullen", "Pinjarra", "Mandurah", "Armadale", "Rockingham", "Baldivis"],
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"], "opens": "06:00", "closes": "18:00" }
],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Water cartage",
"itemListElement": [
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Potable water delivery" }, "priceSpecification": { "@type": "UnitPriceSpecification", "price": "9", "priceCurrency": "AUD", "unitText": "kL" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Non-potable and dust suppression water" }, "priceSpecification": { "@type": "UnitPriceSpecification", "price": "6", "priceCurrency": "AUD", "unitText": "kL" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Delivery — local zone" }, "price": "120", "priceCurrency": "AUD" }
]
},
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "112" },
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "Real customer name from the review feed" },
"datePublished": "2026-02-14",
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "Pulled from Google Business Profile via the operator's review integration — never hand-typed."
}
]
}
What would change for the real client
- Dispatch: the request form drops onto a ServiceM8 or Tradify job card with the purpose, kL, truck and zone as fields, not a text blob; docket photos and signatures come back to the customer by SMS.
- Accounts: Xero invoicing off the completed job, with the standpipe metering export from Water Corporation reconciled against litres delivered.
- ETA texts: a truck GPS / telematics feed (Geotab or MTData) so the "we'll ring back with a window" becomes a live "the 15 is 20 minutes out" text — and a real availability strip on the page for same-day loads.
- Their photos of the trucks and the yard replace the drawn scene where they want it — the Tank Fill stays as the estimator; their reviews come from Google Business Profile; the real phone number and ABN replace the reserved patterns; the LocalBusiness schema above goes live.
- Zone boundaries would be drawn from their actual run sheets, and the "quoted beyond" line replaced by a per-km meter if they want one.
Iteration log
Pass 1 — Craft
- Drove the whole surface: empty submit (panel hidden, four invalid fields flagged), filled submit (panel shown with the prefill), every chip, stepper and toggle, twenty worked scenarios against the oracle — 233 asserts green on the first full run bar four layout/harness items below.
- Screenshot review at 1200 caught the docket covering the whole cab AND the front half of the barrel including the DRINKING WATER placard. Redrew the truck as a bonneted cab (bonnet 44–124, cab 124–262 in scene units) so the barrel starts further back, moved the placard to the rear of the barrel, narrowed the docket to 190 px and anchored it bottom-left. The placard box was also narrower than its text — widened to 152/170.
- 375 masthead measured 4 px over (wordmark 201 → call 217 → book 379): the call icon was being flex-squeezed and the book button read "Book a delivery". Now "Book" below 640 px with `flex-shrink:0` on both; scrollWidth 375, wordmark right 201 < call left.
- Contrast: spec's hover fill
#D0771A measured 4.49:1 under tyre-black labels — re-minted #DA8020 (5.02:1). All other pairs measured ≥ 5.59:1; the full set is in the palette section.
- Shortened the eyebrow, kept "non-potable" from breaking at the hyphen in the h1, and pulled the h1 scale to 60 px max so the trust chips and same-day line sit inside the first 750 px at 1200.
Pass 2 — Depth
- Mid-width check at 1000 (two-column, ~500 px stage) showed the door docket compressing the 10 kL rigid and hiding half the placard — the W37 case exactly. The docket now lies on the pad under the scene between 960 and 1100 px as well as below 640 px, carrying the full note template there (the pinned short form is used only below 640 px). Asserted at 375: badge top ≥ SVG bottom.
- Rest-state price measured $255 from the docket, ledger, mirror and probe; the load line rewrites honestly per state ("NINETY THOUSAND LITRES, NON-POTABLE WATER, THIS MORNING" at 90 kL urgent).
- Second read: the 6 am sun climbs about a pixel every two seconds. Micro-interaction: the docket price bumps 7% on every change (skipped under reduced motion). Rapid-fire drive — eight clicks in one evaluate, then four more — settled consistent with the oracle, zero console errors.
- Badge name uses a short purpose label ("Dust & construction") so the docket never runs to three name lines over the cab.
Pass 3 — Hardening
- 375: no horizontal overflow, sticky bar fixed with the tel link inside the bottom 140 px, h1 + CTA (48 px) + trust chip inside the first viewport; docket strip below the scene at native resolution shows the whole truck, placard and tank.
- Label-collision sweep at native resolution across tank / pool / dust / stock at 800, 1000 and 1200: kL tag and trip counter sit in the sky clear of the docket, the placard sits at the rear of the barrel clear of the docket, the coil tag sits under the barrel; the SAME DAY clock floats above the cab clear of the docket top.
- Reduced motion: no rAF loop, level painted once at the target, truck opacity 1, docket $255 — asserted.
- Keyboard: arrow keys move the chip radios; focus rings visible on chips, switches, steppers, inputs and summaries. Removed one ornament: the stage's four-stop CSS sky-to-gravel gradient went; the sky is now two flat rects inside the SVG and the stage is one flat pad colour, which also lets the docket strip sit on the pad at phone widths.
- Guide checked at 375 (one h1, no overflow, every table in a
.table-scroll wrapper) and both pages carry the colophon verbatim. Serve process killed after the final run.
This is a demonstration build by Sapience Analytics. Want one pointed at your customers?
Dryland Water Cartage is a fictional business — a water cartage industry demonstration designed & built by Sapience Analytics, part of the Generative Assets collection. Back to the site · Index.