Generative Assets · Industry Demos XXVII · site 350
How Southbound Charters was made
A fictional Hillarys fishing charter operator, built as a single conversion-focused landing page whose one job is a booking request with the trip, the seats or the whole boat, and the extras already priced. The wave's dark site — the pen at 5am, deck lights on, the horizon starting to glow.
Concept
Southbound Charters runs reef and deep-drop charters out of Hillarys Boat Harbour on a 12-metre cat: shared seats and private charters across half, full and extended days, bait, ice and the licence covered. The audience is the mate organising a bucks' day, the visiting family who wants to catch a dhufish, the FIFO crew on swing and the corporate team lead. The page has a single job — a booking request with the deck plan already set — and everything on it (the Deck Plan, the ledger, the pre-filled form, the weather-call promise) exists to shorten the distance to that request.
Southbound Charters is a fictional business — a fishing charter industry demonstration designed & built by Sapience Analytics, part of the Generative Assets collection. Phone numbers use the reserved (08) 9000 0xxx pattern, the ABN and the CFL charter licence are placeholders, and the reviews are demo copy on a page that says so.
Palette
Argued from the pre-dawn sea, foam on the hulls, the first orange light over the harbour wall and the teal braid on the reels. Contrast ratios below are measured from the shipped tokens (WCAG arithmetic run in the headless pass), not spec-time hypotheses.
#101C2C pre-dawn navyPage ground. Panels lift to #182739 and #1F3145.
#E4EEF2 sea foamBody ink. 14.55:1 on the ground (spec ≈14). Soft ink #B9C8D2 measures 10.01 / 8.83 / 7.74 on ground / panel / panel-2.
#F08A3C dawn orangeCTA fill with navy labels: 6.86:1 (spec ≈8 — under the hypothesis but well over 4.5). Orange copy on the ground 6.86, on panel-2 5.31.
#F5A86B orange-inkThe pre-minted lighter variant, used for every small orange line on lifted cards (toggle prices, notes): 8.73 on the ground, 6.75 on panel-2.
#3FA7A0 braid tealLines and marks only — swell lines, rods, chip outlines, rules. 5.92 on the ground but never asked to carry small copy.
#7FCCC6 teal-inkTeal-coloured small copy (eyebrows, control labels, ledger declarations): 9.27 on the ground, 7.17 on panel-2.
The whiteboard is its own little light-ground palette inside the dark page: marker ink #1B2A3B on #EEF3F5 measures 13.03, the subtitle grey #3C4C5C 7.89, the eyebrow #4A5B6C 6.25, and the note is written in a marker red-orange #A64F1E at exactly 5.00 — the base orange on white would have been 2.23, so the whiteboard note got its own darker ink (the two-token rule running the normal way on a light surface, inside a dark site).
Type
Four seats, full day, lines in by seven
Oswald 600 for display — the condensed, upright letter of a boat name on a transom and a boat-harbour sign; set in caps with a hair of tracking it reads like the wheelhouse whiteboard itself. Mulish for everything you have to read: a wide, friendly humanist sans that stays legible at 15px on a dark ground and doesn't fight the display face. The display moment is the seat count set huge above the controls, rewritten by every chip and stepper tap.
The Deck Plan — signature
A drawn SVG catamaran side-on at the pen: the wharf and its PEN 14 sign to the left, the harbour wall and its beacon to the right, a gradient sky over a teal-lined sea, and the boat itself — two hulls (the far one drawn behind for the cat read), a wheelhouse under a hardtop, a flybridge rail, a mast aft with the pennant. Every control redraws something:
- Anglers stepper — up to ten drawn figures along the near rail with teal rods and a thin line to the water; your party in dawn orange, other guests in foam grey. Drawn cap is 10 = the boat's survey, so the count is always drawn honestly, and the bow tag prints it too ("4 OF 8 SEATS" / "6 ABOARD · PRIVATE").
- Trip chips redraw the horizon while the boat stays at the pen: full day (deep drop, the earliest departure) keeps the sun under the wall with the glow breathing and the stars up, electric-reel boxes on every rod and a dhufish on the aft deck; half day (reef) brings the sun just over the harbour wall with three drawn reef markers bobbing on the horizon; extended day sets a low, red-orange western sun and stacks three eskies on the wharf.
- Booking chips — shared fills the rail to eight with foam-grey guests and flies a small teal burgee; private draws only your party and hoists the orange PRIVATE pennant.
- Toggles — rod & tackle hire draws a rod rack on the forward hardtop; filleting draws a fillet table on the stern platform; pick-up parks a minibus on the wharf.
- The price is the whiteboard hung on the flybridge rail — an HTML overlay sized in container-query units so it scales with the scene: price, "Full day · shared · 4 seats · tackle", and a second marker line ("Shared carries eight — nine up, go private") that appears only at the shared cap.
Motion: one requestAnimationFrame loop rocks the boat (±1.1° and ±1.6px) and breathes the dawn glow between opacity 0.62 and 1.0 — a never-invisible floor rather than phase arithmetic — with dt = min(max(now − last, 0)/1000, 0.05) and a stop on visibilitychange. Swell lines drift, pennants flap and the beacon pulses in CSS. Under prefers-reduced-motion the loop never starts and the boat rests at a fixed 0.4° with the glow at 0.9. Redraws are dual-speed: the first draw staggers the anglers in at 70 ms per figure, every later change at 26 ms, and each handler bumps the render token before touching state so a rapid-fire sequence of taps can never resolve a stale settle.
Why the scene stays pre-dawn
The spec pinned two things that pull against each other: "full day — high sun" for the trip chip, and a rest-state thumbnail of "the cat at the pen … the dawn glow breathing" on the wave's dark site. The rest state IS the thumbnail and the site's whole direction is the pen at 5am, so the scene stays at the pen for every trip and the chips change the horizon's character instead: the deep-drop crew leaves first (sun still under the wall), the reef crew leaves with the sun just up, and the extended-day sky is the low western sun of the run home. Documented here as a deliberate resolution, not an omission.
Pricing model — pinned anchors, measured outputs
GST inclusive. Every figure on the page is computed from these anchors and cross-checked in the QA harness against an independently reimplemented oracle. Measured rest state: $1,140 (full day, shared, 4 anglers, tackle ON = 4 × $260 + 4 × $25).
| Trip | Shared seat | Private (whole boat, 1–10) |
|---|---|---|
| Half day — reef, 5 hrs | $180 pp | $1,600 flat |
| Full day — deep drop, 8 hrs | $260 pp | $2,300 flat |
| Extended day — 10 hrs | $340 pp | $3,000 flat |
| Control | Rule | Semantic |
|---|---|---|
| Anglers 1–10 | Shared mode caps at 8. Private → shared with 9 or 10 forces the count to 8 with the note; back to private restores the prior count. If the user steps the count while in shared, the remembered count is dropped (they've taken over). | FORCED + note, RESTORE on unlock |
| Eight-seat note | "Shared trips carry eight — nine and up, book it private (it's the cheaper trip from nine anyway)." Present at exactly 8 shared however reached; absent at 7. Honesty cross-check: nine seats cost more than the private flat on every trip (1,620 > 1,600 · 2,340 > 2,300 · 3,060 > 3,000). | NOTE on three surfaces (control, ledger, whiteboard) + a11y mirror |
| Rod & tackle +$25 pp | Multiplies the actual head-count in every mode, private included. | LIVE everywhere |
| Filleting +$15 pp | Multiplies the actual head-count in every mode. | LIVE everywhere |
| Pick-up +$35 pp | Live at 2+ anglers on every trip and mode; disabled at 1 with the reason "pick-up runs for two and up — for one, we're a 20-minute drive from the city". The wanted flag survives the disable, so stepping back to two restores the choice. | DISABLE with reason, RESTORE on unlock |
| Included | Bait, ice, safety gear and the charter's fishing licence cover — declared on the ledger, the statement and the mirror; never a line item. Weather call by 6pm the night before — full refund or reschedule. | Declaration |
| Corporate, multi-day, Rottnest / Abrolhos | No number: "quoted on the brief" in the ledger, the grid and the FAQ. | Designed price-less line |
| Worked example | Arithmetic | Measured |
|---|---|---|
| Rest — full, shared, 4, tackle | 4×260 + 4×25 | $1,140, no note |
| Half, shared, 1, all off | 1×180 | $180 (grid floor); pick-up disabled with reason; at 2 → enabled |
| Extended, shared, 8, filleting | 8×340 + 8×15 | $2,840 + note; at 7 → $2,485, note absent |
| Private, full, 10, tackle + filleting | 2,300 + 250 + 150 | $2,700 |
| Private, half, 6 → 3, all off | 1,600 flat | $1,600 at both (stepper changes the drawn party, not the price) |
| Private 10 → shared → private | forced 8×260 → restored | $2,080 with note, then $2,300 at 10 again |
| Rest + pick-up · rest + filleting | 1,140 + 140 · 1,140 + 60 | $1,280 · $1,200 |
| Grid floors | cheapest priced output per service | half $180 · full $260 · extended $340 · private $1,600 — equal to the services grid |
Iteration log
Pass 1 — Craft
Drove every chip, stepper and toggle against the oracle (247 asserts green on the first run) and then LOOKED. Two composition defects the asserts could not see: (1) the whiteboard sat on the wheelhouse wall and hid two of the four drawn anglers standing in front of the cabin — moved the board up onto a drawn flybridge rail so no figure ever stands under it, moved the mast aft (pennant flying to port) and the rod rack forward so nothing hangs behind the price; (2) the sticky right column never stuck — the hero's overflow:hidden made the section its scroll container and pushed the art down 78px at load. Removed the overflow. Also: the eskies moved from the bow deck (a collision with slots 8–9) to the wharf; the sun-reflection stripe was thinned; the rest sky was reset to pre-dawn (see above); the eyebrow shortened so it holds one line at 375. Contrast measured and recorded above — the only figure under its hypothesis is orange/navy at 6.86 vs ≈8, comfortably over the floor.
Pass 2 — Depth
Second-read details: electric-reel boxes appear on every rod only on the deep-drop trip; the beacon on the harbour wall and the wharf lamp pulse out of phase; a faint stay runs from the masthead to the aft deck; the "SOUTHBOUND" name sits on the hull under the orange boot-top. The whiteboard grew a second marker line at the shared cap — and the first driven screenshot of that state showed the taller board dropping onto the anglers' heads, so the board is now anchored by its bottom edge (just above the tallest cap) and grows upward into the sky; at 375 it also hides the mode word and the extras list so it never wraps. The private count tag ("10 ABOARD · PRIVATE") overflowed its pill, so the pill now sizes itself from getComputedTextLength() and refits once the fonts land; the pennant became a notched burgee so PRIVATE never falls into the flag's tip. Filleting moved off the stern platform (hidden behind the wharf end) to a drawn fillet table on the wharf — which is where the spec says the filleting happens. The 375 layout was re-ordered with display:contents so the scene follows the hero copy, then the display line and controls, then the ledger — the reader sees the boat before the knobs. Micro-interaction: chip and toggle borders warm to teal on hover, the tick fills orange, the stepper buttons dim at their limits with the hint text saying why.
Pass 3 — Hardening
Three-width native-resolution screenshot set (375 / 1000 / 1200): masthead line clean at 375 (wordmark right edge well clear of the phone icon and the Book seats button); the whiteboard covers ~29% of the scene width at 375 and ~26% at 1000, over the wheelhouse only, no label under it; count tag, PEN 14 sign, pennant and board never intersect. Reduced-motion path renders a settled boat with the glow held at 0.9. Rapid-fire drives (14 clicks in one evaluate, then a 60-click loop) settle to the oracle figure with zero console errors. An explicit label-collision assert now runs at rest, at the shared cap with every extra on, and at a private ten: the whiteboard's box must not intersect any drawn head, the count tag, either pennant, the PEN 14 sign, the minibus, the eskies or the fillet table. A reduced-motion page (emulated) holds a static transform and still settles with eight figures drawn; chips and steppers activate from the keyboard (Enter / Space) with a visible focus ring. Harness tally: 247 asserts on the first run, 254 after Craft, 261 after Depth and Hardening — zero failures at every stage. Removed one ornament (the second reflection squiggle under a below-horizon sun). Empty submit surfaces four messages and keeps the confirmation panel hidden; a filled submit shows the panel with "Thanks — booking request received … we'd call you back within one business day". Guide tables ship in .table-scroll wrappers and the guide passes the same 375 probe.
Conversion decisions
- Above the fold at 375: the name, "Reef & deep-drop fishing charters out of Hillarys — lines in by seven", a Book seats CTA, a call button and three trust signals (AMSA survey, the skipper's seasons, the 6pm weather call) all sit inside the first 740px.
- The weather call is a trust signal, not fine print. It's the question every first-time charter customer has, so it's in the trust line, the ledger, the FAQ and the confirmation copy.
- The form takes a preferred date as free text ("any Saturday in October") because charter customers book around swings and weekends, and a rigid date input turns a warm lead into a form error. Suburb-or-hotel because the pick-up minibus needs one or the other.
- Deck plan → form handoff: the textarea is pre-filled from the signature ("Booking request: full day (deep drop, 8 hrs), shared seats, 4 anglers, tackle — $1,140 GST inc.") until the visitor edits it.
- Sticky call/book bar below 960px; the header keeps a tel: link at every width. Nothing is charged online: "every booking is a request" is on the ledger, the statement and the promise card, so the demo never pretends to take payment.
Local SEO we'd implement for the real business
The live page carries only WebPage / CreativeWork / BreadcrumbList schema naming it a demonstration — fictional business data must not enter a real index. For the real operator we would ship the block below. schema.org has no charter-specific subtype (no "FishingCharter" or "BoatTourOperator" exists in the vocabulary), so the honest top-level type is LocalBusiness with the trips expressed as Offers in a catalogue; reviews would come from a live feed (Google Business Profile via a reviews widget), never hand-typed.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"@id": "https://www.example-charter.com.au/#business",
"name": "Southbound Charters",
"description": "Reef and deep-drop fishing charters out of Hillarys Boat Harbour on a 12 m catamaran — shared seats and private charters, half, full and extended days.",
"url": "https://www.example-charter.com.au/",
"telephone": "+61 8 9xxx xxxx",
"image": "https://www.example-charter.com.au/img/southbound-at-the-pen.jpg",
"priceRange": "$180–$3,000",
"address": {
"@type": "PostalAddress",
"streetAddress": "Pen 14, Hillarys Boat Harbour, Southside Drive",
"addressLocality": "Hillarys",
"addressRegion": "WA",
"postalCode": "6025",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -31.8249, "longitude": 115.7382 },
"areaServed": ["Hillarys", "Perth", "Scarborough", "Joondalup", "Two Rocks"],
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"], "opens": "06:00", "closes": "19:00" }
],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Charters",
"itemListElement": [
{ "@type": "Offer", "name": "Half-day reef seat", "price": "180", "priceCurrency": "AUD" },
{ "@type": "Offer", "name": "Full-day deep-drop seat", "price": "260", "priceCurrency": "AUD" },
{ "@type": "Offer", "name": "Extended-day seat", "price": "340", "priceCurrency": "AUD" },
{ "@type": "Offer", "name": "Private charter (whole boat, up to 10)", "price": "1600", "priceCurrency": "AUD" }
]
},
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "212" },
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "Real customer name from the reviews feed" },
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "Pulled from Google Business Profile — never hand-written."
}
],
"sameAs": ["https://www.facebook.com/…", "https://www.instagram.com/…"]
}
</script>
Alongside the schema: a Google Business Profile with the pen as the pin, service-area pages for the pick-up suburbs, a "what's biting" post cadence tied to the season (dhufish closure dates are real content people search), and FAQ schema on the licence and weather-call questions.
What would change for the real client
- Bookings
- Rezdy or FareHarbor for live seat inventory, deposits and the OTA channels (Viator, GetYourGuide) — the Deck Plan would query availability per date and hand off to the checkout with the trip, seats and extras pre-selected.
- Accounts
- Xero — deposits, invoices for private charters, the fuel and bait lines.
- Weather call
- A BOM or Willy Weather feed on the booking page (swell, wind at Rottnest) with the 6pm decision pushed by SMS to every booked angler — the promise the site makes, automated.
- Photos & reviews
- Real deck photos in place of the drawn cat, a live Google reviews widget in place of the three demo cards.
- Licence & safety
- The real CFL number, AMSA survey certificate number and the Fisheries charter licence conditions in the footer; the bag-limit FAQ linked to the current DPIRD recreational fishing rules.
Techniques
- Single-file HTML, all CSS/JS inline; only Google Fonts loaded externally. No raster images anywhere — the scene, the map and the icons are inline SVG; the sky, sea and glow are SVG gradients.
- SVG scene with a whiteboard as an HTML overlay in
cqwunits (container-type:inline-sizeon the scene), with a tight variant under 560px and a mid-width variant between 561 and 1100px. - rAF loop with clamped delta and visibility pause; CSS keyframes for the swell lines, flags and lamps;
prefers-reduced-motionhonoured in CSS and viamatchMedia. No canvas, so no DPR cap is needed; the SVG rescales on resize by construction. - State probe
window.__fishingchartersexposes the scenario, computed figures, the display line, board text and asettledflag; QA gates on state, never on seconds. - Procedural SVG coastal map: depth contours, the trench dashed in orange, the three-mile reef and the towns from Two Rocks to Fremantle, Hillarys starred.
This is a demonstration build by Sapience Analytics. Want one pointed at your customers?