Generative Assets · Industry demo 225 · guide

How Second Shot Espresso was made

A fictional Mount Hawthorn café and caterer, built as a single conversion-focused landing page. The page has two jobs: get a local through the door tomorrow morning, and — primarily — get an office or event organiser to submit a catering enquiry. Everything else serves those two.

Concept

Second Shot Espresso — the name is the promise: if the first shot isn't right, the second's on the house. Dark espresso warmth, the 6am glow of a bench light on timber, editorial food confidence with zero bistro cliché. The audience splits in two — Mount Hawthorn regulars checking hours on a phone, and office managers pricing Friday morning tea — so the hero sells the walk-in and the very next section sells the catering.

Palette — argued from the cup

Dark roast#241B15 the ground — a pulled shot, not a black default
Crema#EFDFC8 body ink on roast — 13.7:1, effortless reading
Caramel drizzle#C9853F LINE/MARK only — pour lines, plate rims, rules, the primary CTA
Caramel ink#E4AF74 derived for small labels — caramel fails 4.5:1 at label size, this clears ~8.7:1
Matcha#8FA86B the one cold-drinks accent — form focus, map suburbs, juice bottles

The caramel is deliberately never used for body-size text — it draws the drizzle lines, plate rims and the total's progress rule, while #E4AF74 carries eyebrows and price labels. Matcha is rationed to a single role per section so the warm field stays warm.

Type

Fraunces (variable) is the food-world serif with the wonk to carry a café's charm without a chalkboard in sight. The axes are used deliberately: the h1 and wordmark run 'SOFT' 80–100, 'WONK' 1 — full soft-serif warmth with the wonky a and e; section headings pull back to 'SOFT' 55, 'WONK' 0 so the wonk stays a voice, not a tic. Work Sans does everything utilitarian — menu prices, form labels, body — at ≥16px on mobile.

The signature: the Catering Builder

A headcount stepper (6–120, ±6 per tap, direct entry allowed) and three package chips drive a procedural SVG counter scene. The scene composes rather than multiplies: each package has its own item grammar — morning tea lays trays (one per 8 heads), lights the urn at 12, stacks cups per 24, brings fruit out at 36 and a second urn at 60; lunch boxes stack kraft columns of four, chill juices at 24, add the urn at 30 and a fruit crate at 40; grazing lays boards (one per 12), brings fruit at 24 and stacks the cheese tower at 40. When the front bench fills, a back riser shelf appears and the layout wraps onto it — 6 heads is a single tray, 120 fills both shelves. Items are string-templated SVG groups re-laid on every change; new items animate in with a placed-down pop (staggered 45ms), and under prefers-reduced-motion the bench renders fully laid with no draw-on.

The maths is the conversion argument: the total is computed live (heads × rate, $150 minimum spend rounding small orders up, both shown honestly: 6 heads × $22.00 = $132.00 with a visible min-spend note) and a caramel drizzle rule under the total lengthens with the spend. At rest the scene shows a worked example — 24 heads, morning tea, $228.00, bench mid-laid — so the static preview already demonstrates the interaction. Builder → form handoff: one button carries the configured headcount, package and quoted total into the enquiry form, turning the toy into a warmer lead. Live state is exposed at window.__cafe for testability.

Conversion decisions

Techniques

Vanilla single-file: no libraries. The bench scene, hero cup, service icons and delivery map are all inline SVG — the map is a stylised inner-north with a 5 km ring centred on Mount Hawthorn, nine named suburbs and Lake Monger as the one landmark locals orient by. Gradients do the 6am light: a radial caramel glow clipped by the pendant's cone polygon. Entrance choreography is CSS-only (staggered rise keyframes gated on a js-ready class, with a no-JS fallback that leaves everything visible). The [hidden]{display:none !important} guard protects the form/confirmation swap from any authored display rule.

Local SEO we'd implement for the real business

This demo page ships only WebPage schema naming it a demonstration — fictional structured data in a real index is dishonest markup. For a real café we'd ship:

{
  "@context": "https://schema.org",
  "@type": "CafeOrCoffeeShop",
  "name": "…",
  "servesCuisine": "Coffee, breakfast, catering",
  "telephone": "+61 8 …",
  "address": { "@type": "PostalAddress", "addressLocality": "Mount Hawthorn",
               "addressRegion": "WA", "postalCode": "6016", "streetAddress": "…" },
  "geo": { "@type": "GeoCoordinates", "latitude": -31.92, "longitude": 115.84 },
  "openingHoursSpecification": [
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
      "opens": "06:00", "closes": "14:00" },
    { "@type": "OpeningHoursSpecification", "dayOfWeek": "Saturday",
      "opens": "06:30", "closes": "13:00" }
  ],
  "hasOfferCatalog": { "@type": "OfferCatalog", "name": "Catering packages", … },
  "aggregateRating": { … from the live Google reviews feed, never hand-written … }
}

Plus suburb-level landing content for the delivery ring (Leederville, North Perth, Wembley…), Google Business Profile with the catering menu attached, and review schema fed from the real reviews source only.

What would change for the real client

Iteration log

Pass 1 — Craft

Drove the full suite headless (40 asserts): rest state 24 × $9.50 = $228.00 exact, chips at 30 heads ($285 / $495 / $660 hand-checked), extremes 6 (min spend $150 applied, note visible) and 120 ($2,640.00, riser appears, zero items out of the 760-unit scene), empty submit (5 fields flagged) and filled submit (confirmation renders, form hides).

Looked at the screenshots and caught what the asserts couldn't: "THE SECOND SHOT" caption clipped at the hero art's right edge; the free-shot glass floating above the ground line with no shadow; the 375 trust line landing 14px below the fold because the hero sub ran 8 lines. Shortened the sub to three lines, tightened mobile hero padding, grounded the glass, moved the caption — and raised the header tel pill to 44px min-height.

Pass 2 — Depth

Wired the drizzle rule under the total to the spend: a caramel fill (a real block element — W12's invisible-inline-span lesson) that lengthens from 6% to full as the total approaches the $2,640 maximum, asserted at 6 heads (~24px) and 120 heads (~394px). Added the second-read details: the two house cups that never leave the bench (the second shot, always poured), urn steam on a 3.2s ease loop, and a caption easter egg past 70 heads that points standing-function crowds at the room hire. Stepper buttons got press-down feedback.

Screenshots reviewed: desktop hero now clean at the right edge, 375 shows h1 + CTA + all three trust chips above the fold with the sticky bar clear of the content.

Pass 3 — Hardening

Reduced-motion verified end-to-end: rm class set, hero settled at opacity 1, bench fully laid with zero draw-on items, steam stilled, smooth-scroll dropped. Focus-visible matcha outlines on every control; FAQ toggles keyboard-clean; date input min enforces the 48-hour notice in the picker itself. Chanel rule: removed the "Scene drawn live" tag from the bench caption — the scene demonstrates itself. Final copy read for internal consistency: $9.50 floor, $150 min spend, 5 km ring, 48 hours and 46/70 capacity each appear identically everywhere they're quoted. Final suite: all asserts green, zero console errors, one h1 per page, 375 scrollWidth clean on both pages.

Second Shot Espresso is a fictional business — a hospitality industry demonstration designed & built by Sapience Analytics, part of the Generative Assets collection. All names, reviews, prices and registrations on the demo page are illustrative.