Generative Assets · Industry Demos · how it was made
How the Hullcare Marine demo was built
Hullcare Marine is a fictional Henderson antifoul, haul-out and hull care yard — power boats, yachts and catamarans to 15 m lifted, washed, antifouled and relaunched. The page exists for one reader: the owner due for the annual slip who wants the boat, grade and extras priced and a days-on-the-hard figure before they bring her round. Its single job is a slip booking with the scenario already attached.
The Slipway Quoter
The signature element is a drawn SVG boat standing in a hardstand cradle at the Henderson slipway: the water band and jetty behind, the tide lapping at the slipway edge, a gull-shadow crossing the wet concrete, the hull in profile with its copper-red antifoul band below the boot-top. Every control redraws the scene honestly and reprices the slip from the pinned per-metre rates:
- Length 5–15 m stretches the drawn hull linearly (54 scene units per metre — a 15 m hull is 810 units of the 1080-wide scene, so there is no drawn cap; the dimension tag prints the true LOA).
- Hull chip redraws the boat: power monohull (cuddy cabin to 7 m, cabin and flybridge from 8 m, transom and skeg rudder), sailing keelboat (mast, boom, forestay, fin keel, spade rudder) or catamaran (two hulls in three-quarter view on the wide cradle with bridgedeck cabin, two props).
- Grade chip switches the antifoul band between matte ablative and a gloss highlight for premium self-polishing; prop speed lights the prop and shaft with a coating highlight (two on the cat); anodes draws the zinc discs on hull and shaft; cut & polish lays a gleam stripe and a sparkle along the topsides; extra days adds tally strokes to the job tag.
- The price badge is the cradle's job tag, hung from a shackle on the rail end by a drawn string. Two lines always — the total and "back in the water in <2 + extra + (polish ? 1 : 0)> days" — plus the declaration footnote "+ any hull repairs found on the hard, quoted". On-scene at ≥641 px, docked beneath the cradle inside the signature's container at ≤640 px.
- The big-lift note ("over 12 m we lift on the 40-tonne travel lift — same per-metre price, book a week ahead"; short form ≤640 px "over 12 m: the 40-t lift, book a week ahead") appears on power or sail at 13 m and above, never on the cat.
- The catamaran chip caps the stepper at 12 m: lengths 13–15 are disabled on the rail with the reason on-page, a longer hull is forced to 12 when the chip is chosen, and chipping back to power or sail restores the remembered length.
Pinned anchors (GST inclusive, per metre of LOA)
| Hull | Haul-out, wash, 2 nights & relaunch | Standard ablative | Premium self-polishing | Props | Anode set | Floor (5 m, standard, nothing) |
|---|---|---|---|---|---|---|
| Power monohull | $60 / m | $150 / m | $195 / m | 1 | $140 | $1,050 |
| Sailing keelboat | $65 / m | $165 / m | $215 / m | 1 | $140 | $1,150 |
| Catamaran (to 12 m) | $95 / m | $240 / m | $310 / m | 2 | $220 | $1,675 |
Prop speed coating is $180 per prop and multiplies the hull's actual prop count; the anode set is flat per hull; topsides cut & polish is $55 per metre of LOA and adds a day; extra hardstand days are $60 each, 0–5. Osmosis and blister repair, rudder bearings, through-hulls and skin fittings carry no number anywhere — "quoted after haul-out" on the badge footnote, the ledger, the screen-reader mirror and the FAQ. Every rate is a whole dollar and length is a whole metre, so no total ever needs rounding.
Worked examples measured from the running page
| Scenario | Arithmetic | Total | Days | Note |
|---|---|---|---|---|
| Rest state — keelboat, 10 m, premium, prop speed, anodes, cut & polish, 0 extra | 650 + 2,150 + 180 + 140 + 550 | $3,670 | 3 | absent |
| Power, 5 m, standard, nothing (grid floor) | 300 + 750 | $1,050 | 2 | absent |
| Catamaran, 12 m, premium, 2 props, anodes, polish, 2 extra days | 1,140 + 3,720 + 360 + 220 + 660 + 120 | $6,220 | 5 | absent (cat) |
| Power, 8 m, standard, polish | 480 + 1,200 + 440 | $2,120 | 3 | absent |
| Sail, 13 m, standard, nothing | 845 + 2,145 | $2,990 | 2 | present |
| Sail, 12 m, standard, nothing (boundary pair) | 780 + 1,980 | $2,760 | 2 | absent |
| Power, 14 m, standard → cat chip → forced to 12 → power chip | 2,940 → 1,140 + 2,880 → restored 14 m | $2,940 → $4,020 → $2,940 | 2 | present → absent → present |
| Rapid-fire: length 5 → 15 → 9, hull power → sail → power in one evaluate | 540 + 1,350 | $1,890 | 2 | absent |
All eleven worked figures, the cheapest-output floors ($1,050 / $1,150 / $1,675, equal to the services grid), the 180 ↔ 360 prop-count reprice and the 140 ↔ 220 anode reprice were cross-checked against an oracle reimplemented from the anchors in the verification harness, not from the page's own code — 250 assertions in the final pass (236 on the site, 14 on this guide), all green.
Palette — argued from Cockburn Sound haze
Sea-haze ground, navy ink and navy CTAs, an antifoul copper-red band for the hull below the waterline and for the marks, and the grey-blue of a wet hardstand. Contrast ratios below were computed with WCAG arithmetic from the shipped tokens in Pass 1 (role, hex and ratio from the same script row).
Pass 1 measurement moved two tokens: the ledger's "not selected" lines were first set in a mid grey (#6B7F8A, 4.18:1 on white) and now use sea-ink (6.36:1); the map's water labels were white over the water gradient (2.35–3.75:1) and are now navy ink with a pale halo. Every other spec figure measured within 0.1 of its computed hypothesis.
Type
The display moment is the rest-state line set over the cradle — "10 M KEELBOAT · PREMIUM · BACK IN 3 DAYS · $3,670" — rebuilt from state on every change, so the figures are always the live total and days; the separators travel with the token that follows them (a non-breaking space after each middle dot) so a wrap never strands a dot at a line end.
Techniques
- Procedural SVG scene, no libraries. The backdrop (sky and water gradients, far shore, jetty, channel marker, slipway rails, hardstand joints and a puddle) is drawn once; the boat, cradle, dimension tag, tag string, tide and gull live in a dynamic group rebuilt on every state change. Hull profiles are parametric paths (stern, run, forefoot, stem, sheer) whose freeboard and draught scale with length; the antifoul band is a rectangle clipped by the hull path, the boot-top a thin clipped stripe, the gloss a clipped highlight stroke.
- Dual-speed redraw (W21). First paint staggers each drawn part at 26 ms (1.4 s cap); every later state change redraws at 10 ms per part with a 500 ms cap via a
firstDrawflag — a stepper tap feels instant, the first load earns its choreography. Parts animate opacity only (never a property they also set as an SVG attribute). - Token-invalidated loop (W25). The tide (a 37-point path redrawn each frame with a slow lap and two sine terms) and the gull + shadow pair run in one requestAnimationFrame loop whose token is bumped in every control handler before the state swap; the loop exits on the next frame, the rebuilt scene starts a fresh one, and the probe's
loopscount settles back to exactly one — asserted after two rapid-fire bursts. Delta time is clamped at zero and capped at 50 ms (W29); the loop idles while the tab is hidden. - Job tag placement. The HTML badge is positioned from the SVG's rendered scale: its hook sits under the rail-end shackle, the string is a quadratic path from shackle to hook, and when a tall tag (note + tally) would run past the scene frame the holder grows its padding instead of the tag covering the controls. At ≤640 px a narrower viewBox crops the scene and the tag docks below as a two-column strip.
- Reduced motion. CSS media query plus a
matchMediacheck: no loop starts, the tide and gull are painted once at a settled phase, the entrance transitions are disabled and the hero's rise animation is off. - State probe.
window.__antifoulcarries hull, length, grade, toggles, every ledger line, the total, days, note strings, locked lengths, prior length,loopsand asettledflag (set after the redraw cap) — QA gates on state, never on seconds.
Conversion decisions
- Above the fold at 375 px: business name, "Antifoul, haul-out and hull care at Henderson — power boats, yachts and cats to 15 m, back in the water in days", Book a slip + Call (08) 9000 0365, and the est. 2012 / 40-tonne lift / $20M liability trust line — all inside the first viewport, measured.
- Call vs book: slip bookings are calendar work, so the primary CTA is "Book a slip" with the phone a visible ghost button; on phones a sticky bar carries Call now + Book a slip above the thumb.
- The quoter feeds the form. Hull, length, grade, extras, the total and the days line pre-fill the booking textarea; "Book this slip" refreshes it and focuses the name field. Form fields are the ones a yard needs to hold a cradle: name, mobile, home pen (Fremantle / Cockburn Sound / Rockingham / Mandurah / Hillarys / trailer boat), boat name (it goes on the cradle tag) and the details block.
- Honest floors. The services grid's "from" prices are the Quoter's cheapest outputs per hull — $1,050 / $1,150 / $1,675 — and the days template, the big-lift note and the "quoted after haul-out" declaration appear wherever the total does. The cat stepper stops at 12 m with the reason on-page rather than computing a lift the yard can't do.
- Local confirmation, no fake network. Empty submit flags the required fields inline and keeps the confirmation hidden; a valid submit shows the designed panel ("Thanks — slip request received. We'd call you back within one business day…") naming the boat and the estimate, clearly marked as a demonstration.
Local SEO we'd implement for the real business
The live page carries only WebPage, WebSite and BreadcrumbList structured data naming it a demonstration — a fictional yard must not mark itself up as a real one. For the real client we would ship the block below. schema.org has no boat-repair or marina-services subtype, and AutoRepair would be wrong (it is a vehicle type the yard doesn't service and would mislead rich results), so the top-level type is the plain organisation type LocalBusiness with the service named through additionalType and knowsAbout. Real reviews would be pulled from Google Business Profile and marked up only with the reviewer's consent.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"additionalType": "https://www.wikidata.org/wiki/Q1050307",
"name": "Hullcare Marine",
"description": "Antifoul, haul-out and hull care at Henderson — power boats, yachts and catamarans to 15 m.",
"url": "https://www.example-hullcare.com.au/",
"telephone": "+61 8 9000 0365",
"image": "https://www.example-hullcare.com.au/yard.jpg",
"priceRange": "$$",
"address": {
"@type": "PostalAddress",
"addressLocality": "Henderson",
"addressRegion": "WA",
"postalCode": "6166",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -32.16, "longitude": 115.77 },
"areaServed": ["Fremantle", "Cockburn Sound", "Rockingham", "Mandurah", "Hillarys", "Mindarie"],
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"], "opens": "06:30", "closes": "16:00" }
],
"knowsAbout": ["antifouling", "boat haul-out", "travel lift", "propeller coating", "sacrificial anodes", "gelcoat cut and polish", "osmosis repair"],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Slipway services",
"itemListElement": [
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Haul-out, wash and antifoul — power boats" }, "priceSpecification": { "@type": "PriceSpecification", "price": "1050", "priceCurrency": "AUD", "description": "from, 5 m LOA, standard ablative" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Haul-out, wash and antifoul — yachts" }, "priceSpecification": { "@type": "PriceSpecification", "price": "1150", "priceCurrency": "AUD", "description": "from, 5 m LOA, standard ablative" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Haul-out, wash and antifoul — catamarans to 12 m" }, "priceSpecification": { "@type": "PriceSpecification", "price": "1675", "priceCurrency": "AUD", "description": "from, 5 m LOA, standard ablative" } }
]
},
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "87" },
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "Real customer, with consent" },
"datePublished": "2026-03-14",
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "Pulled from the live Google Business Profile feed — never hand-written."
}
]
}
</script>
Alongside the schema: a Google Business Profile with the slipway pinned, "antifoul Henderson" / "boat haul-out Fremantle" / "catamaran lift Perth" as the page's core phrases with the suburbs above as secondary, NAP consistency across the marina directories and the Boating Industry Association listing, and a reviews feed that updates without anyone touching the page.
What changes for the real client
- Bookings and job cards: Tradify or ServiceM8 for the slip booking, the job card that travels with the boat and the cradle tag — the Quoter's scenario becomes the job's line items, not a textarea.
- The hardstand calendar: a live cradle/lift calendar behind the "Book a slip" form so the owner sees real lift dates, with the 40-tonne lift as its own resource for hulls over 12 m.
- Xero for the invoice the moment the hull is back on the pen; the estimate maps line-for-line onto the invoice.
- Supplier feeds for antifoul stock — International and Jotun are the kind we'd wire — so the grade chips reflect what's actually on the shelf, and the maker's spec sheet links from the grade card.
- The yard's own photographs of lifts, keels and finished topsides, a Google reviews feed, the real ABN and insurance certificates, and the real phone number in place of the reserved pattern.
Iteration log
- Pass 1 — Craft. Contrast measured from the shipped tokens: the ledger's "not selected" grey failed (4.18:1) and moved to sea-ink; the map's white water labels (2.35–3.75:1 over the gradient) became navy ink with a pale halo; every other figure matched its computed hypothesis. The boat read small at 44 units per metre — scaled to 54 with deeper freeboard/draught so a 10 m keelboat fills the cradle and a 15 m hull still clears the frame. The display line was wrapping with a middle dot stranded at the line end — the separators now travel with the token that follows them. Dimension label lifted to 16 px with a wider halo; the premium gloss highlight strengthened (it was too faint to read as a sheen); the rest scene re-checked at 1200×750 with the $3,670 tag inside the thumbnail.
- Pass 2 — Depth. A 5 m runabout drawn as a flybridge cruiser looked dishonest, so power hulls to 7 m now draw a cuddy cabin with a raked screen and targa bar, and the cabin-plus-flybridge profile starts at 8 m. The catamaran's far hull was hidden behind the near hull (22/−28 offset); pushed to 34/−46 so both hulls, the far band and the bridgedeck read as two hulls on the wide cradle. The prop-speed mark gained a sparkle cross instead of an arrow-shaped glint; the tag string became a quadratic curve from a drawn shackle on the rail end to the tag's hole; the gull in the sky and its shadow on the hardstand are one paired loop (second-read detail) with the flap in the gull's scale. Pass 2 drove every worked example, the force-to-12 / disabled 13–15 / restore-to-14 sequence, the 180 ↔ 360 and 140 ↔ 220 reprices and two rapid-fire bursts — all green, one loop after each burst.
- Pass 3 — Hardening. At 1200 a tall tag (big-lift note + four tally strokes) hung past the scene frame and over the controls — the holder now grows its padding by the overflow; the 375 masthead measured wordmark right 186 px vs call button left 238 px (no collision), scrollWidth 375 with zero offenders, sticky bar in the bottom 140 px, h1 + CTA + trust line inside the first viewport; the mobile viewBox crop was retuned after the scene shift (80 30 920 400) so the cradle rail stays in frame; reduced motion verified (no loop, settled still-water scene, controls still work); the v-flag form patterns were checked in Node and surfaced no console errors; the Chanel rule removed the second puddle under the tag; final copy read in Australian English. Also checked: the badge docks below the scene at 640 and sits on-scene at 641; FULL note form at 1000 (mid-width) and 641, SHORT form at 640.
One spec semantic resolved by the builder: the restore-on-unlock remembers the forced-from length only while the owner leaves the cat's length alone — if they step the length while the cat chip is active, that explicit choice wins and chipping back to power or sail keeps it. The pinned 14 → cat → 12 → power → 14 sequence is asserted as written.
This is a demonstration build by Sapience Analytics. Want one pointed at your customers?