Generative Assets · Kerbside Mechanical · build notes

How the mobile-mechanic demo was built

Kerbside Mechanical is a fictional Canning Vale mobile mechanic, built as a one-page industry demonstration: a landing page whose single job is turning "I can't lose the car for a day" into a booked driveway slot — with the price already settled before anyone calls.

The concept

The audience is a commuter, a parent timing a service around school pickup, or a used-car buyer who wants a lemon caught before the money moves. The page's answer is the Driveway Job Board: a side-profile SVG scene of the Kerbside van at the kerb and the customer's car on the driveway, where tapping vehicle-class and job chips lights tool markers on the car and paints the priced total straight onto the van's panel. The board's scenario then pre-fills the booking form, so the enquiry arrives already scoped.

Palette — the driveway at 7am

Argued from the subject: concrete underfoot, a navy work van, one signal-orange work light, steel tools. Contrast figures below are measured WCAG ratios from the shipped tokens, not estimates.

Driveway concrete#EFF1F3page ground
Workshop navy#1E2A3Abody ink — measured 12.81:1 on the ground
Signal orange#C2410Cwork-light sweep, marks and lines only — measured 4.57:1 on the ground, so it never carries small text
Button orange#A63A0ACTA fills — white labels measure 6.50:1
Orange ink#8F3407orange-coloured copy and links — measured 6.97:1 on the ground
Tool steel#9AA6B5car linework, callouts, rules — lines and marks only

The two-token orange pair is the point: the argued hue (#C2410C) stays for the work light and marks, while buttons get the deeper #A63A0A fill under white labels and orange-coloured text uses #8F3407. The mid-tone accent never labels small text.

Type

Barlow Condensed (600–700) carries the display — a signwriter's condensed that reads like the lettering on a van panel, which is exactly where the biggest number on the page lives ("$320, in your driveway"). Barlow handles body copy at 16.5px: same superfamily, so the page keeps one voice from headline to form label. Caps with tracked spacing do the wayfinding (eyebrows, chip labels, ledger total); sentence case does the talking.

The Driveway Job Board — implementation

The scene is one hand-drawn SVG (760×380): kerb and driveway as a single stroked ground path, the van with its painted panel, and three vehicle silhouettes (small hatch / SUV / 4WD ute) toggled by hidden attribute with a [hidden]{display:none!important} guard. The front wheel is a shared group at a fixed arch position across all three classes — so the front-brakes marker can lean it off against the sill (a CSS transform on an inner group; the outer group owns the positioning attribute, keeping SVG attribute state and CSS animation on separate elements). Each job marker — propped bonnet and checklist board, exposed rotor with caliper, gauge manifold on its stand, battery with a hanging QUOTED tag, clipboard-and-magnifier — is an outer positioning group wrapping an inner .marker group that transitions opacity/transform.

Dual-speed redraw: the first render runs the 900ms entrance; after it, a --mdur CSS variable drops to 480ms so every chip tap redraws snappy. Every handler bumps a token and clears the probe's settled flag before the state swap, and the settle timer only marks settled if its token is still current — no stale in-flight animation can outlive a rapid-fire tap sequence.

Work-light sweep: a radial-gradient ellipse under the bonnet, driven by one rAF loop with the delta clamped at zero and capped at 50ms. Opacity oscillates between 0.55 and 1.0 — a never-invisible floor, so the thumbnail capture can land at any instant and the signature still reads alive. Reduced motion gets a settled frame at 0.85; the loop pauses on document.hidden.

The badge is the display moment: the computed total is painted on the van's side panel inside the SVG, inside the first 750px at 1200 wide — the thumbnail carries the commercial argument, not just the art.

The honest pricing model

Total = sum of selected jobs at the selected class. The class chip re-prices the logbook and brakes only — the regas and pre-purchase inspection are flat, and both say so on their chips ("same gas, same gauge, any car"). Every cell of the class × job matrix is live; there are no disabled combinations on this board.

Rates as shipped (AUD, whole dollars — all totals are integer-safe by construction)
JobSmall hatchSedan & SUV4WD & ute
Logbook service$260$320$380
Front brakes$340$390$450
Air-con regas & leak check$180 — flat at every class
Pre-purchase inspection$230 — flat at every class
Battery supply & fitno number by design — "priced by the battery your car takes; quoted before a tool comes out"
  • Zero-selection state: with no job picked the badge reads "$ — / pick a job to price" — a designed prompt, not an error. The services grid's floor is the cheapest priced output, the $180 regas, never $0.
  • Battery declaration: the battery is an authority-of-the-part price — any printed figure would be a guess. When selected, the ledger prints "+ battery at quoted price" and the badge appends "+ battery"; with the battery alone the badge itself becomes the declaration ("+ battery / at quoted price"). The declaration appears wherever a total does.
  • Travel: callout included within 25 km of Canning Vale (the labelled ring on the map); beyond it +$1.20/km each way — a stated copy line beside the map and in the FAQ, deliberately not an estimator control, because a customer shouldn't need to measure their own crow-flies distance to get a number.
  • Rest state: sedan/SUV with the logbook service — $320, measured from the running page and equal to the services grid's sedan/SUV logbook anchor.

Conversion decisions

  • Above the fold at 375px: value proposition naming the trade and the area, the book CTA, the tel link, and the MRB licence chip — the board follows immediately after, so the first scroll lands on the price.
  • Click-to-call everywhere: tel link in the masthead, in the hero, beside the form, and in a solid-background sticky bar on mobile (no backdrop-filter — it composites black in headless renderers).
  • The board pre-fills the form: the priced scenario lands in the job textarea, so the demo interaction becomes a warmer lead. With nothing selected it hands over the class alone and the form still submits.
  • Form fields: name, phone, suburb-the-car-sleeps-in, vehicle make & model — the minimum a real dispatcher needs to confirm a slot. Validation is front-end only; the confirmation panel is hidden on load and on an empty submit, and appears only after a valid filled submit, saying plainly that this demo sends nothing anywhere.
  • Honesty framing: reserved (08) 9000 0330 number, placeholder ABN/MRB/ARC patterns, a colophon that names the fiction, and demo reviews labelled as demo copy. Live JSON-LD is limited to WebPage/WebSite/BreadcrumbList — the business-shaped schema lives below as a code sample, not in the index.

Local SEO we'd implement for the real business

A real Kerbside Mechanical would ship AutoRepair structured data — the exact schema.org subtype for this trade — wired to their real NAP, hours, and a live review feed. This demo keeps its index clean of fictional business markup, so the would-ship schema sits here as a code sample instead:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "AutoRepair",
  "name": "Kerbside Mechanical",
  "description": "Mobile mechanic servicing driveways and workplaces across Perth.",
  "telephone": "+61-8-9000-0330",
  "url": "https://kerbsidemechanical.com.au",
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Canning Vale",
    "addressRegion": "WA",
    "postalCode": "6155",
    "addressCountry": "AU"
  },
  "areaServed": { "@type": "City", "name": "Perth" },
  "openingHoursSpecification": [
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
      "opens": "07:00", "closes": "17:00" },
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Saturday", "opens": "07:00", "closes": "13:00" }
  ],
  "priceRange": "$180–$890",
  "aggregateRating": {
    "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "187"
  },
  "review": {
    "@type": "Review",
    "reviewRating": { "@type": "Rating", "ratingValue": "5" },
    "author": { "@type": "Person", "name": "A real customer" },
    "reviewBody": "Wired to the live review feed, never hand-written."
  }
}
</script>

For the real client this page would also swap in: their photos and van livery, a live Google review feed, online booking through MechanicDesk or ServiceM8 (both do mobile-workshop scheduling well), and Xero for the invoice rail the demo only gestures at.

The three iteration passes

Pass 1 — Craft

  • Measured every contrast hypothesis from the spec with real WCAG arithmetic: body ink 12.81:1 (spec's ≈12 confirmed), base orange 4.57:1 on the ground (right on the spec's ≈4.5 — confirming it stays a marks-only token), button orange under white 6.50:1 (better than the spec's ≈5.5), orange ink 6.97:1, badge caption on the van navy 9.49:1. All recorded above; nothing needed re-minting beyond the spec's pre-minted pair.
  • The 375px screenshot caught the licence trust chip sitting behind the mobile sticky bar — the fold requirement failed visually while a naive "within 667px" assert passed. Shortened the hero sub on mobile (desktop keeps the full line), tightened hero paddings, and hardened the assert to "trust chip clears the sticky bar's top edge". The whole above-fold set — h1, sub, both CTAs, licence chip — now fits at 375×667.
  • The board card's kicker (h2 + "tap to price" hint) fought for one row at 375 and wrapped awkwardly; stacked it into a column below 680px.
  • The propped checklist board overlapped the van's rear corner in the scene; moved it 16px right onto the kerb line. Masthead measured clean: wordmark right edge ~166px vs call-link left edge ~257px.

Pass 2 — Depth

  • Drove every binding worked example with the full control vector set explicitly and asserted badge, ledger line and total against an independently reimplemented oracle: rest $320 · SUV logbook+brakes+regas $890 · 4WD logbook+brakes $830 · the class-swap intersection re-pricing the brakes line 340→450 with brakes held ON · small logbook+battery "$260 + battery at quoted price" on both badge and ledger · PPI alone $230 at two classes · regas alone $180 · battery alone rendering the "+ battery / at quoted price" declaration badge · the empty-selection "$ — pick a job to price" prompt. All matched the oracle exactly, first run.
  • Rapid-fire drive (seven chip clicks in one evaluate, no settle between): the handler-side token invalidation held — the settled frame matched the oracle for the derived end state (4WD, logbook+regas+ppi, $790) with zero console errors.
  • Added the badge flash: when the painted price changes, an orange wash sweeps the van panel for half a second — the price change reads even in peripheral vision.
  • Added the second-read detail: the propped LOGBOOK board ticks off one checklist row per stacked job, so a three-job quote shows three orange ticks. Sweep floor measured over 30 samples at 100ms: min 0.550, range 0.45.

Pass 3 — Hardening

  • 375px sweep on both pages: scrollWidth clean at 375 on index and guide; this guide's rates table ships in its scroll container with a deliberate min-width.
  • Empty submit after a hard reload: 4 invalid fields flagged, confirmation panel stayed hidden. Filled submit: panel shown with the callback promise, form hidden. The phone pattern was written against Chrome's v-flag regex rules (every literal special escaped) and the zero-console-errors assert stayed green across every drive.
  • Reduced-motion path verified by emulation: transitions collapse via the media query, the sweep renders a settled 0.85-opacity frame with no rAF loop running, and smooth scrolling drops to auto.
  • Chanel rule: removed the van's second decorative roof-rack line — one line reads as a roof rack, two read as clutter.
  • Final thumbnail check at 1200×750: the scene, the van-panel $320 badge and the h1 all inside the first 750px. Sticky call bar tappable at 375 with 48px targets inside the bottom 140px. Full harness: 74 asserts, 74 green.

Techniques, in short

  • Hand-authored SVG scene and metro map — every visual procedural, no raster anywhere.
  • Vanilla JS state machine (~200 lines): one compute() as the single pricing source of truth feeding badge, ledger, chips and the window.__mobilemechanic state probe.
  • CSS transitions for all marker choreography (outer group owns SVG position attributes, inner group animates), one rAF loop for the light sweep with zero-clamped, 50ms-capped deltas.
  • No libraries — Google Fonts is the only external resource.