Design & engineering guide · Industry demonstration
How Boronia & Bay was built
The concept
Boronia & Bay is a fictional Subiaco flower studio, named for brown boronia — the WA winter flower whose scent sells out every July. The audience is someone who needs flowers somewhere today: birthday, sympathy, anniversary, apology. The page has one job — an order enquiry, with the 1 pm same-day cutoff doing the urgency work honestly — and one signature, the Bouquet Bench, a procedural SVG bouquet that composes itself stem by stem while the ticket beside it stays as disciplined as an invoice.
Palette — botanical warmth against studio cream
#FAF5EC — the ground; kraft paper's paler cousin.#37322A — all body text, 11.6:1 on cream.#4C6B4F — foliage fills, links, ticks.#D98A80 — petals and CTAs; marks and blooms, never small text.#8C4A52 — the flower's deep bell; eyebrows and accents.#C4A171 — the wrap tone, inside the illustration and the occasion word.The ink/line split rule applies throughout: blush and kraft carry marks and blooms; text sits in stem-brown (or green-ink for links) at ≥4.5:1. The blush CTA carries stem-brown ink text at ≈4.8:1 rather than white at ≈2.8:1.
Type
Gloock (display) has the high-contrast, hand-lettered elegance of a flower-shop window — it carries the wordmark, headings, the ticket total, and the typographic bravery moment: the occasion word set huge in the bench, crossfading as you change occasion. Karla does the working text; the order ticket uses its tabular figures so every price lines up like an invoice.
The signature — the Bouquet Bench
The bouquet is pure procedural SVG, deterministic per selection. A seed hashed from size + palette + occasion feeds a mulberry32 PRNG, so the same choices always compose the same bouquet, and changing the occasion genuinely changes the stems — never the price, which the ticket states outright.
- Composition: bloom tips are placed by golden-angle phyllotaxis over a dome ellipse (posy 7 stems, classic 12, abundant 18), jittered, then sorted back-to-front by y so heads overlap naturally. A collar ring of greenery sprigs fills the silhouette edge, and each palette carries its own bloom recipes — boronia bell clusters, waxflower, billy buttons and gum foliage for WA natives; layered roses, stock spikes and sage for pastels; gerberas, tulips and hot-pink roses for brights.
- Draw-in: stems draw with stroke-dash reveals, kept
visibility:hiddenuntil drawn length > 0 (the W15 round-cap dot), leaves fade in along the path viagetPointAtLength, and blooms pop at the tips with an ease-out-back scale on a nested group — the outer group holds the SVG transform attribute, the inner one animates, so CSS never discards attribute state (W16/W17). - Dual-speed redraw: the first compose takes the full ~2.3 s entrance choreography;
every subsequent change replays snappy, capped around 0.6 s via a
firstDrawflag (W21). - Race safety: every control handler bumps the compose token before touching state, so a mid-compose swap abandons the in-flight rAF timeline cleanly (W25) — verified with a nine-click rapid-fire drive in one evaluate.
- Rest state: classic natives, fully composed and gently breathing (a CSS sway on a nested group, never below full opacity), ticket showing $95 + $15 = $110, the 1 pm chip visible — and the bench card shares the 1200 × 750 thumbnail frame with the hero. Reduced motion renders the settled, fully-composed frame immediately.
The honest pricing model
Every figure is pinned anchor arithmetic, cross-checked in the verification harness against an independently reimplemented oracle across all 24 size × add-on combinations.
| Item | Rule | Worked example (measured) |
|---|---|---|
| Posy | $65 | Posy + chocolates = $83 + $15 = $98 |
| Classic | $95 | Rest state: $95 + $15 delivery = $110 |
| Abundant | $140 | $140 ≥ $120 → delivery free → $140 |
| Glass vase | +$25 | Classic + vase = exactly $120 → delivery flips FREE → $120 total |
| Chocolates | +$18 | Classic + chocolates = $113 → still $15 delivery → $128 (below threshold) |
| Handwritten card | free | Changes the ticket and the card copy, never the total |
| Delivery | $15 same-day metro, order by 1 pm; free at $120+ subtotal (add-ons count) | Threshold asserted at precisely $120, and at $113 just below |
- Occasion and palette are visual-only — the ticket carries the statement "the occasion changes the stems, not the price" (every occasion and palette was driven in the harness and asserted to hold $95/$15/$110 at rest).
- Grid floor: the services grid's "from $65" equals the bench's cheapest bouquet.
- Subscription pinned flat at $55/week: a standing-order rate below the one-off posy — one planned Thursday run, one rate, the drive built in. The flatness is the deliberate pricing statement, shipped on-card.
- Designed price-less lines: events & weddings are "quoted on consult" and sympathy work is "coordinated with the venue" — deliberate states, not missing data.
Conversion decisions
- Above the fold at 375 px: wordmark + phone in the masthead, the h1 promise ("Same-day flowers across Perth — order by 1 pm"), blush order CTA, call link with hours, and three trust chips — all inside the first viewport.
- The bench pre-fills the form: "Order this bouquet" writes the full selection — size, palette, add-ons, total, card copy — into the enquiry notes and sets the occasion select, turning a play interaction into a warm lead.
- The free-delivery hint sells honestly: below $120 the ticket says exactly how many dollars away free delivery is; at the flip it strikes the $15.
- Mobile sticky bar: call + order, 56 px targets, on every phone-width view.
- Form: name, phone, delivery suburb, delivery date, occasion — the fields a florist actually needs for a callback; v-flag-valid phone pattern; graceful local confirmation ("Thanks — your order enquiry is received… we'd call you back within the hour") that names the suburb and declares the demo honestly.
Local SEO we'd implement for the real business
This demonstration page deliberately ships only WebPage schema
naming it a demonstration — fictional structured data in a real index would be dishonest
markup. For a real florist we would ship:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Florist",
"name": "Boronia & Bay",
"telephone": "+61-8-XXXX-XXXX",
"priceRange": "$65–$140",
"address": {
"@type": "PostalAddress",
"streetAddress": "…",
"addressLocality": "Subiaco",
"addressRegion": "WA",
"postalCode": "6008",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -31.95, "longitude": 115.82 },
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "08:00", "closes": "17:00" },
{ "@type": "OpeningHoursSpecification",
"dayOfWeek": "Saturday", "opens": "08:00", "closes": "14:00" }
],
"areaServed": { "@type": "City", "name": "Perth" },
"aggregateRating": { "@type": "AggregateRating",
"ratingValue": "4.9", "reviewCount": "180" },
"review": [{
"@type": "Review",
"author": { "@type": "Person", "name": "…" },
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "…"
}]
}
</script>
— fed by the real Google Business Profile and a live reviews feed, never hand-written.
What would change for the real client
Their bouquet photography (or this procedural art kept as a brand system), their reviews feed, and real commerce: a florist POS/e-commerce platform such as Floranext, Lovingly or Shopify + Square for orders and payment; relay membership (Interflora/Petals) if they take network orders; delivery-run routing via Locate2u or Zoom2u with SMS "it's at the door" notifications; an address/suburb autocomplete on the form; and a live cutoff clock wired to the studio's actual run schedule — the demo keeps the 1 pm rule static rather than faking a countdown.
Iteration log
Pass 1 — Craft
The first bouquet read as sparse sticks: fan-angle stem placement scattered small blooms with big gaps, and a long narrow kraft cone dominated the frame. Rebuilt the composition — golden-angle phyllotaxis dome sampling, back-to-front y-sorting, a wider/shorter wrap, bloom scale up ~1.7–2.2×, larger gum/sprig foliage, and a greenery collar ring. Fixed a truncated services line ("delivery in" → "delivery included"). Harness after the pass: 89/90 (the one failure was this guide not existing yet).
Pass 2 — Depth
Added the second-read details: a kraft care tag ("cut 6 am") swinging off the twine on its own CSS-animated nested group; a petal-drift micro-interaction — tapping the bouquet releases five palette-matched petals that fall, sway and clean themselves up (reduced-motion-guarded); the occasion word now crossfades instead of hard-swapping; and the delivery line strikes through the $15 when the $120 threshold flips it to FREE. New asserts: tag present, petals spawn and self-remove — 92/93.
Pass 3 — Hardening
375 px sweep: masthead measured wordmark-right vs phone-left (no collision), sticky-bar
targets ≥56 px, scrollWidth 375 on both pages, h1 + CTA + trust chip inside the first
viewport. Reduced-motion path renders the fully-composed settled frame with all animation
killed. Rapid-fire nine-click drive confirmed the compose token holds under abuse. Chanel
rule: removed the twine knot-cross ornament (two twine bands and the tag carry it) and gave
the ticket aria-live="polite". Final sweep with this guide included: 100/100
asserts, zero console errors, every displayed figure matching the independent oracle.
Techniques
- Procedural SVG illustration throughout — bouquet, metro delivery map (Subiaco starred), service icons, favicon. No raster images anywhere.
- Deterministic seeded composition (FNV-hash → mulberry32) per selection.
- Stroke-dash draw-ins, path-following foliage, ease-out-back bloom pops, token-based animation invalidation, dual-speed redraw.
- State probe
window.__florist(selection, subtotal, delivery, total, settled) so QA gates on state, never on seconds. - Headless verification: puppeteer harness with an independently reimplemented pricing oracle, 24-combination sweep, exact-threshold assert at $120, hard-reload empty-submit, filled-submit lexicon check, reduced-motion and 375 px probes, screenshot review each pass.