Gatherwell Party Hire

Build notes · Industry demo

How the Gatherwell Party Hire page was made

Gatherwell is a fictional Balcatta marquee & party hire operator built to show what Sapience Analytics would ship for a real one: a landing page whose signature — the Marquee Planner — turns "how big a marquee do I need?" into a priced, itemised weekend plan that walks itself into the enquiry form. Every visual is procedural SVG and CSS; there isn't a raster pixel on the page.

Palette — golden hour on white canvas

Argued from the subject: white marquee canvas, dusk plum for the hour the festoon takes over, berry punch for the celebration, brass for the bulb wire. All contrast figures below are measured WCAG ratios from the shipped tokens (the spec's figures were treated as hypotheses and verified in Pass 1).

Linen canvas#F6F5F1 — page ground; folded-tablecloth crispness.
Dusk plum#2B2630 — body ink, measured 13.53:1 on linen.
Muted plum#6A6070 — secondary ink, measured 5.47:1 on linen, 5.97:1 on white cards.
Berry punch#A83A57 — CTAs and links; measured 5.65:1 on linen, white button text 6.16:1 on berry.
Festoon brass#A98A45 — measured 3.0:1, so it is a lines-and-marks token only: marquee linework, bulb wire, valance. Never small text.

Type

DM Serif Display is the occasion invitation — high-contrast, a little formal, exactly the register of an engagement party. It carries the headings and the planner's typographic bravery: the guest count set huge in words (FORTY GUESTS) that re-spells itself as the stepper runs. Mulish is the workhorse — a warm humanist sans that stays legible at 13px ledger rows and 16.5px body on a phone.

The Marquee Planner

An SVG backyard — fence palings, lawn, golden-hour sun — with a marquee redrawn from data on every state change. The planner always quotes the smallest marquee that fits the guest count for the selected mode (seated capacities 24/48/96; cocktail 40/80/150), states it on-card, and lets an upsize toggle step one size up for weather room. Seated mode computes and draws trestle tables (one per eight guests) and every chair; cocktail clears them for bar tables — "cocktail means standing, that's the point". The dance floor is disabled on the 6×3 with its reason printed, and the upsize toggle disables at the 10×6 ("the biggest on the truck"). The computed weekend price lives inside the artwork as a badge on the marquee roof, with the $200 refundable bond declared under it — the bond prints wherever the total does and is never added to it.

The festoon glow sweep

Bulbs are sampled along the swag path with getPointAtLength, and a single persistent requestAnimationFrame loop drives a warm pulse bulb-to-bulb. Each bulb's opacity is 0.55 + 0.45·pulse — a never-invisible floor of 0.55 so the string reads lit at any screenshot instant — and the bulb nearest the sweep phase is pinned to full 1.0. The frame delta is clamped at zero and capped (dt = min(max(now−last,0)/1000, .05)), the loop pauses on document.hidden, and every control handler bumps an animation token before the scene swap so a mid-sweep rebuild can never leave a stale closure driving removed nodes. Festoon off leaves the string drawn and the bulbs unlit; reduced motion renders the string statically lit with no sweep.

Dual-speed redraw

The first render earns the entrance choreography — scene elements fade in on a stagger capped at ~1.05 s. Every subsequent stepper tap or toggle rebuilds the scene instantly, with only the price badge given a 280 ms settle-pop so the number lands with weight instead of lag.

The pricing model (pinned anchors)

ItemRateRule
6×3 m marquee$480 weekendseats 24 · cocktail 40
8×4 m marquee$760 weekendseats 48 · cocktail 80
10×6 m marquee$1,250 weekendseats 96 · cocktail 150
Trestle tables$16 each1 per 8 guests, rounded up (seated)
Chairs$4 each1 per guest (seated)
Bar tables$20 each1 per 10 guests, rounded up (cocktail)
Festoon lighting+$120 / $160 / $220priced by the marquee delivered
Parquet dance floor 4×4 m+$380fits from the 8×4 up — disabled on the 6×3
Mushroom heaters+$95 each0–4
Security bond$200 flatrefundable — declared with every total, never added to it
Crockery, linen & stylingno numberquoted from the runsheet — a designed price-less line

All prices are weekend hire, delivered, rigged and collected metro-wide. Every worked example in the spec was measured on the running page and cross-checked against an independently reimplemented oracle: rest state $1,160 (40 seated, festoon on); the seated boundary pair $624 at 24 guests (6×3, no step-up) and $924 at 25 (8×4, with the size note); the cocktail boundary pair $560 at 40 (6×3 exactly) and the 8×4 step at 41; $2,616 for the full 96-guest build; $904 for 24 seated upsized (which brings the dance floor live); and the $500 grid floor (10 guests cocktail) that equals the services grid's "from $500". The festoon string is priced by the marquee actually delivered, so an upsize re-prices the string honestly.

Conversion decisions

Iteration log

Pass 1 — Craft

Measured every contrast hypothesis from the spec: dusk plum landed 13.53:1 (spec ≈13), berry 5.65:1 (spec ≈5.6), and a muted plum ink was minted at #6A6070 (5.47:1) rather than letting brass near text — brass measured 3.0:1 and stays a line token. The screenshot review caught the roof price badge still faded out at the capture instant: the entrance stagger totalled ~2.4 s across ~90 scene elements, so the badge — drawn last — risked missing the 7-second thumbnail; the stagger is now capped at ~1.05 s. At 375px the masthead "Get a quote" button wrapped to two lines and broke the header rhythm — fixed with nowrap and tighter padding. Removed a dead conditional left in the scene-draw path.

Pass 2 — Depth

Gave the price badge a settle-pop (scale .92→1, 280 ms) on subsequent redraws only, so a stepper tap reads as the number landing rather than the scene lagging. Stopped the glow rAF loop entirely when festoon is off instead of letting it idle. Widened the badge 160→176 and dropped its figure to 20px after the rest-state text sat tight against the plate edges. The second-read detail: the marquee valance carries a tiny letter-spaced GATHERWELL wordmark, the way real hire canvas is branded.

Pass 3 — Hardening

The map's Scarborough label collided with the Balcatta depot star — moved clear. Chanel rule: the service-area map had two dashed delivery rings; one says it better, the outer ring went. Verified the reduced-motion path (static lit festoon, no sweep, hero visible), the empty/filled submit pair driven on button[type=submit] specifically, a rapid-fire burst of mode/stepper/toggle clicks with no settle between (token invalidation held — zero errors), and the full worked-example suite against the oracle. Final run: 61 probes green, zero console errors on desktop, 375, reduced-motion and guide passes; no horizontal overflow at 375 on either page.

Local SEO we'd implement for the real business

This demo page deliberately ships no business structured data — fictional LocalBusiness/Review markup in a real index would be dishonest. For a real Gatherwell, we'd ship this. schema.org has no party-hire subtype, so the honest top-level type is LocalBusiness with an additionalType pointing at an equipment-rental concept:

{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "additionalType": "http://www.productontology.org/id/Equipment_rental",
  "name": "Gatherwell Party Hire",
  "description": "Marquee and party equipment hire — 6x3, 8x4 and 10x6 marquees,
    seating, festoon lighting and dance floors, delivered across Perth.",
  "slogan": "The party, delivered.",
  "telephone": "+61-8-9000-0324",
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Balcatta",
    "addressRegion": "WA",
    "postalCode": "6021",
    "addressCountry": "AU"
  },
  "areaServed": "Perth metropolitan area",
  "openingHoursSpecification": [
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
      "opens": "07:00", "closes": "17:00" },
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Saturday", "opens": "07:00", "closes": "12:00" }
  ],
  "priceRange": "$500-$2,600",
  "aggregateRating": {
    "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "87"
  },
  "review": [{
    "@type": "Review",
    "author": { "@type": "Person", "name": "Priya M." },
    "reviewRating": { "@type": "Rating", "ratingValue": "5" },
    "reviewBody": "Rain came in sideways and the marquee didn't move.
      Bond back by Tuesday."
  }]
}

What would change for the real client

The planner's rate card would read from the client's live hire inventory — Booqable or HireHop both expose availability and pricing APIs, so "is the 8×4 free on the 14th?" becomes a real answer, not a callback. The enquiry form would write straight into the same system's booking pipeline, invoicing and the $200 bond refund would run through Xero, and the reviews would be a live feed instead of demo copy. Their photos would join the drawn scene, not replace it — the planner stays, because it's the thing a competitor's template can't do.

Back to the Gatherwell site · Generative Assets index