Redgum Bakehouse

Making Redgum Bakehouse — the build guide

Site 321 in the Generative Assets collection, and one of its industry demonstrations: a conversion-first landing page for a fictional Bassendean artisan bakery, built to show a real bakery owner exactly what we’d build for them.

Concept

4:30am at the ovens

Redgum Bakehouse is a fictional artisan bakery and celebration-cake kitchen in Bassendean — the audience is parents ordering a birthday cake that has to arrive intact, couples pricing a christening or engagement cake, and locals who want the Saturday sourdough held. The page has one job: an order enquiry with tiers, finish and delivery already priced.

The art direction is the hour before opening: flour-dust warm ground, dark cocoa ink, caramelised-crust CTAs and rattan proofing-basket linework. Everything a photograph would normally do — the cake, the van, the shopfront map — is drawn procedurally in SVG instead, in the site’s own palette. Unhurried craft; the page should feel like the smell of the first bake.

Palette

Flour, crust and the proofing basket

The spec’s contrast figures were hypotheses; every ratio below was measured from the shipped tokens with WCAG relative-luminance arithmetic during Pass 1.

Flour dust#F7F2E8 — page ground; the bench before wipe-down.
Dark cocoa#2A231E — body ink, measured 13.9:1 on flour; also the oven-dark footer.
Caramelised crust#A8571F — CTAs and links, measured 4.7:1 on flour (spec hypothesised 4.9:1 — corrected); white button text measures 5.2:1 on it.
Crust, well-baked#8A4617 — hover state and the ticket’s price ink, measured 6.3:1 on flour.
Proofing rattan#C09B5E — 2.3:1 on flour, so it is LINES and marks only: cake linework, basket-weave rules, the river on the map. Never text.
Toasted ink#5E5248 — the derived muted-text token, measured 6.8:1 on flour; carries captions and chalk labels the rattan can’t.

Footer inks on the oven dark: #F0E8D9 measures 12.7:1 and the muted #BFB2A2 measures 7.4:1 — both comfortably past the 4.5:1 floor.

Type

A loaf-shouldered serif and a workhorse

Display — Young Serif, 400

TWO TIERS, FIFTY SERVES

Young Serif ships exactly one weight, and that constraint is the point: warm, round-shouldered, hand-drawn in feel — a chalkboard menu, not a lifestyle magazine. The typographic bravery moment is the tier count set huge above the drawn cake, swapping as the stepper does.

Body — Figtree

Figtree carries everything else — labels, prices, form fields — at 16.5px body size. A bakery page is read one-handed at a kitchen bench; legible and friendly beats expressive here, and its slightly rounded terminals keep it in the same warmth as the serif.

Signature

The Tier Builder

The signature is an SVG celebration cake on a drawn cake stand that is priced as it’s built. The tier stepper (1–3) stacks drawn tiers, each chalk-labelled with the serves it takes the cake to; flavour chips recolour the crumb through a cutaway slice on the bottom tier (and the crumb-streaks of the semi-naked finish); finish chips restyle the exterior — buttercream gets palette-knife swirls, semi-naked drags crumb streaks through a thin wash, fondant smooths the radius and adds a sheen. A piping line loops a decorating pass over the top tier. The topper toggle draws an acrylic topper, the delivery toggle parks a van beneath the stand, and the price ticket leaning against the stand recomputes live — the price is part of the artwork, because the thumbnail is the commercial argument.

Implementation: the tiers, labels, piping and topper are rebuilt synchronously from state on every change (handlers token-invalidate in-flight animation before the state swap, so rapid-fire clicks can’t strand a stale closure). The piping pass is a dash-offset loop over a scallop path with a ghost copy held at 0.55 opacity underneath — the signature is visibly piped at any capture instant, and the live stroke stays hidden until its drawn length exceeds zero so no round-cap dot leaks at rest. The rAF loop clamps its delta at zero and caps it at 50ms, pauses when the document hides, and never starts under prefers-reduced-motion (the piped pass renders settled instead). Entrance choreography runs on first draw only; every later change redraws snappy (~420ms settle) via a firstDraw flag.

Pinned anchors (all prices in whole AUD)

ItemPriceNote
1 tier · serves 24$160the grid floor — “cakes from $160”
2 tiers · serves 50$310the rest-state base
3 tiers · serves 90$520 
Buttercream / semi-naked+$0the base finishes, stated on-card
Fondant+$60 a tiernote templated: “fondant adds $<60 × tiers>”
Flavour chips+$0price-inert by design — the drawn crumb always responds
Acrylic topper+$25live in every state
Delivery & setup, metro+$60 flatcollection from Bassendean free, stated on-card
Fresh-flower stylingno numberflorist’s stems billed at cost — the declaration is the price
Dessert tables & weddingsno numberquoted after a tasting — designed price-less state

Worked examples, measured from the running page

ScenarioArithmeticDisplayed
Rest state: 2 tiers, semi-naked, lemon curd, delivery on310 + 60$370
3 tiers, fondant520 + 3×60$700
2 tiers, fondant, topper, delivery310 + 120 + 25 + 60$515
1 tier, buttercream, no extras160$160

Every displayed figure was verified against an independently reimplemented oracle in the headless harness — the page’s cheapest output ($160) equals the services grid’s “from $160” floor.

Conversion decisions

Why the page is shaped like this

  • The builder shares the fold with the promise. At 1200×750 the thumbnail shows the headline, the drawn cake mid-piping, and the $370 ticket — the price badge is inside the artwork because a ledger below the fold doesn’t make the capture.
  • Builder → form handoff. The configured cake pre-fills the order form’s summary line and textarea (until the visitor edits it, after which we never overwrite their words). A priced enquiry is a warmer lead than a blank one.
  • Honest controls. Flavour never changes the price and the card says so plainly (“pick with your heart”) while still repainting the crumb — a control that visibly responds but honestly no-ops on price. Fresh flowers print no number at all: stems are billed at cost, and the declaration is the deliverable.
  • Two price-less states by design. Dessert tables are “quoted after a tasting” — a designed state, not missing data.
  • Click-to-call everywhere. Header tel link, hero secondary CTA, sticky mobile call/order bar — bakery customers are a phone in one hand and a toddler in the other.
  • The form asks only what the first call needs. Name, phone, suburb, date needed — plus the pre-filled cake line and the occasion. Everything else is the callback’s job (“within one baking day” — a promise that also tells you it’s a real bakery’s morning).
  • Honest FAQ answers as trust signals. Low-gluten friendly, not coeliac-safe; we match the idea, not the watermark; serves counted in coffee-shop slices. A bakery that says no clearly is a bakery you believe about everything else.

Techniques

Everything is drawn

  • Procedural SVG throughout — the cake, stand, van, flour sack (his name is Russell), the metro map with the Bassendean star and the “cakes travel metro-wide” ring. No raster images anywhere.
  • Dynamic SVG rebuild from a single state object; SVG visibility is toggled via the hidden attribute (never the IDL property) with a [hidden]{display:none !important} guard, and animated groups carry no SVG transform attribute so CSS animation can’t discard layout.
  • Dash-draw piping loop with a 0.55-opacity ghost floor, zero-clamped rAF delta, visibility-pause, and a reduced-motion settled frame.
  • Entrance choreography gated on document.fonts.ready with a fallback timer and a no-JS guard class, so content never sticks at opacity 0.
  • State probe window.__bakery exposes tiers, flavour, finish, toggles, total, serves and a settled flag — the QA harness gates on state, never on seconds.

Process

Three passes over the bench

Pass 1 — Craft

  • Measured every palette claim with WCAG arithmetic: crust on flour came in at 4.7:1, not the spec’s hypothesised 4.9:1 — still past the 4.5 floor for links, so the hue stayed and the measured figure is recorded above. Rattan measured 2.3:1 and stayed lines-only; the muted-text job went to a minted toasted ink at 6.8:1.
  • Drove the builder headlessly to all four pinned worked examples against an independent oracle — $370 rest, $700, $515, $160 floor. The first run’s only red was a harness fault: the driver ran the “3 tiers, fondant = $700” example with the rest state’s delivery still on, and the page honestly showed $760. Fixed the driver to drive the pinned scenario; the site’s arithmetic never moved.
  • Screenshot review at native zoom cleared a suspected stray line through the price ticket’s sub-text — a downscale artifact of the capture, not a defect; the zoomed clip renders clean.
  • Empty submit raises four validation marks and keeps the confirmation panel hidden; filled submit (clicking button[type=submit] specifically) shows the panel with the configured cake, price and date echoed back.

Pass 2 — Depth

  • The rest-state capture showed ~140 viewBox units of dead headroom above the two-tier cake — space reserved for three tiers plus a topper. The viewBox now crops to the built cake per state with the width fixed at 720, so the crop never rescales the drawing; the card just breathes with the cake.
  • Added piped bead dots along each tier’s base for the coated finishes — the detail a real finished tier carries — and nudged Russell the starter clear of the price ticket.
  • Rapid-fire drive: six control clicks in one evaluate, twice over, including tier swaps mid-piping — no stale-closure errors, state and oracle agree at the end; handlers bump the invalidation token before every state swap.
  • Confirmed the semi-naked exterior picks up the selected crumb colour in its dragged streaks (asserted on the drawn strokes, not just state) — flavour visibly responds even though it’s price-inert.

Pass 3 — Hardening

  • 375px sweep on both pages: no horizontal overflow, masthead line clean (wordmark right edge vs call-pill left edge compared explicitly, 237 < 277), sticky call/order bar present with 44px targets, and the guide’s pricing tables scroll inside their own wrappers.
  • The sticky header’s 97%-alpha background let the display serif ghost through it once the page scrolled — made the header and sticky bar fully opaque (headless Chrome and conversion chrome don’t mix with translucency).
  • Reduced-motion path renders the cake fully piped and settled with zero animation loops running; the settle frame shows the piped cake, lemon crumb, van and $370 ticket, with signature and price both inside the first 750px at 1200 wide.
  • Chanel rule: removed the fondant tiers’ white “sheen” stroke — at card size it read as a stray mark, and the fondant already reads through its radius, colour and beading.
  • Zero console errors across load, drives, submits and viewport changes; the form’s pattern is v-flag-safe. Final suite: 63 asserts, all green.

Local SEO

What we’d implement for the real business

This demo page carries only WebPage schema naming it a demonstration — fictional structured data in a real search index is dishonest markup. For a real bakery client, schema.org has the exact subtype — Bakery — and we’d ship it with real NAP, real hours and the shop’s real review feed:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Bakery",
  "@id": "https://redgumbakehouse.com.au/#bakery",
  "name": "Redgum Bakehouse",
  "url": "https://redgumbakehouse.com.au",
  "telephone": "+61 8 XXXX XXXX",
  "priceRange": "$7–$700",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "… Old Perth Road",
    "addressLocality": "Bassendean",
    "addressRegion": "WA",
    "postalCode": "6054",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": -31.909, "longitude": 115.944 },
  "openingHoursSpecification": [
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Wednesday","Thursday","Friday","Saturday"],
      "opens": "06:00", "closes": "13:00" },
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Sunday", "opens": "07:00", "closes": "11:00" }
  ],
  "servesCuisine": "Bakery",
  "areaServed": "Perth Metropolitan Area",
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.9",
    "reviewCount": "184"
  },
  "review": [{
    "@type": "Review",
    "author": { "@type": "Person", "name": "A real customer" },
    "reviewBody": "Pulled from the shop's live review feed — never invented.",
    "reviewRating": { "@type": "Rating", "ratingValue": "5" }
  }]
}
</script>

Aggregate figures and reviews would be fed from the bakery’s actual Google Business Profile — structured data earns the rich result only when it’s true.

For the real client

What would change with a real bakery

  • Their cakes, their counter. The drawn cake stays as the builder’s interactive core, but a real gallery of their finished cakes sits alongside it — the drawing prices, the photos persuade.
  • Orders into their tools, not an inbox. The enquiry would land in Bake Diary (the cake-order diary most WA cake kitchens already run) with deposits taken through Square POS — the same terminal as the counter trade — and the lot reconciled in Xero. No double entry, no Saturday-morning phone tennis.
  • A real availability signal. The oven diary’s lead-time (“next free cake weekend: …”) rendered on the page from Bake Diary’s calendar — scarcity that’s true converts better than urgency that isn’t.
  • Real reviews, real schema. The Google Business Profile feed replaces the demo reviews, and the Bakery schema above goes live with their NAP and hours.

← Back to the Redgum Bakehouse demo · Generative Assets index