Concept
Straightline Panel & Paint is a fictional smash repairer in Wangara, serving Perth's northern corridor — the audience is a not-at-fault driver holding a claim number, a car-park dent victim deciding whether to claim, and fleet operators with sign-written utes. The page has one job: get a photo estimate or an assessment booked. The art direction is the spray booth at noon — craft under even light, zero crash-scene drama; the wreck is the past, the page is about the repair.
Palette — argued from the booth
Type
- Saira Semi Condensed (display) — the condensed capitals of a workshop hoarding. The hero's three-line stack ("Straight lines. Matched colour. Like it never happened.") is the page's one moment of typographic bravery.
- Karla (body/UI) — a warm workhorse grotesque that stays legible at 16px on a phone in a car park.
- Overpass Mono — panel codes, price bands, hours, the booth stencils. Everything that would be lettered on a job card is set in mono.
Techniques
Everything is procedural: the sedan, the booth, the map and every icon are inline SVG; the light cones and wall are layered gradients; motion is CSS transitions gated on document.fonts.ready with a no-JS fallback and a full reduced-motion path. No canvas, no libraries — a conversion page for a 4G phone.
The signature: the Damage Mapper
A hand-plotted sedan side profile (920×340 viewBox) carries eight tappable panel paths — each with role="button", tabindex="0", aria-pressed and a keydown handler that dispatches a real MouseEvent (SVG elements have no .click()). A transparent 14px stroke widens each hit area for thumbs. Damage renders on the selected panel into a layer clipped by that panel's own path via <clipPath><use>: scuffs are hatched strokes, a dent is a radial-gradient shadow with a highlight arc, a crease is a butt-capped line pair along the swage, and "smashed" builds crumple facets plus radiating crack lines. Respray severities also tint the neighbouring panels in dashed primer — the blend zone, which is the trade's honest answer to "why does one panel quote three surfaces". A booth job-tag (PNL 03 · FRONT GUARD) tracks the selection — the second-read detail. Every selection pre-fills the enquiry form with panel, severity, payment mode and the current band, and updates the window.__panelbeater state probe.
The pricing model — derivation
The spec pinned the severity "from" anchors; the panel factor table is derived here and documented so QA has a source of truth. Private mode computes band = severity base × panel factor, rounded to the nearest $10. Insurance mode disables the price output with the on-page reason that the assessor sets the figure — a disabled control with a reason beats a dishonest number.
Severity base bands (steel panels)
| Severity | Band | Why |
|---|---|---|
| Scuff | $150 – $210 | Buff + machine polish; no paint touched. |
| Small dent | $180 – $310 | PDR — worked from behind, factory paint kept. |
| Crease | $580 – $730 | Repair + respray, blended into neighbours. |
| Smashed | $980 – $1,420 | Panel replace + paint; teardown checked. |
Panel factors
| Panel | Factor | Argument |
|---|---|---|
| Front / rear door, sill | 1.00 | The baseline flat panel; sill's small area offsets its low working height. |
| Front guard | 1.07 | Bolt-on, but wraps into bumper and bonnet gaps; blends two neighbours. |
| Bonnet | 1.20 | The largest horizontal face — read under full sun, dearest to spray flawless. |
| Rear quarter | 1.25 | Welded, not bolted — repair-biased, blends into door, sill and boot. |
Bumpers (plastic substrate — override table)
| Severity | Band | Why |
|---|---|---|
| Scuff | $150 – $210 | Same machine-polish work as steel. |
| Small dent | disabled | PDR works steel from behind; plastic gets repaired and resprayed — the chip disables with that reason on-page. |
| Crease / scrape | $450 – $620 | Plastic weld + flex primer, sprayed as a complete unit off the car. A bar is its own colour break, so no blend — which is why bumper repairs start under a panel respray. |
| Smashed | $980 – $1,380 | New bar + paint + fitment; tabs, absorbers and sensors checked. |
Measured worked example (rest state): front guard × crease = $580×1.07 = $620.60 → $620; $730×1.07 = $781.10 → $780. The spec's ≈$620–$780 hypothesis measured out exactly under the derived factors — shipped as $620 – $780. The model's cheapest output (scuff × factor 1.00 = $150) equals the services grid's "from $150" buffing floor, and the $180 / $450 / $580 / $980 grid anchors are each the model's own minima for their scenario — the page never argues with itself. Blend honesty is stated where it applies: a resprayed steel panel quotes three surfaces; a bumper doesn't.
Conversion decisions
- Mapper in the hero. At desktop the Damage Mapper is the hero's right column, mid-demonstration at rest (front guard, crease, private, $620–$780 showing) — the "that could be my site" moment happens in the first viewport, and the estimate card's CTA hands straight into the form.
- Private/insurance toggle up front because "repair or claim?" is the real first question — the FAQ's excess-vs-range maths backs it.
- Form fields: name, phone, suburb, vehicle make/model (parts pricing), optional claim number, and a description that the mapper pre-fills — "photos help" framing because photo estimates are how this trade actually triages. Confirmation is local, instant, and clearly a demo: "Thanks — that's received … we'd call you back within the hour."
- Sticky mobile bar pairs Call with Photo estimate — a smash customer is standing next to the damage with a phone in hand.
- Choice-of-repairer honesty gets its own banner: it's the single most valuable thing a WA driver doesn't know, and saying it plainly is the trust play.
Local SEO we'd implement for the real business
This demonstration deliberately ships only WebPage schema naming it a demo — fictional structured data in a real index is dishonest markup. A real Straightline would ship LocalBusiness + Review schema like this:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "AutoBodyShop",
"name": "Straightline Panel & Paint",
"telephone": "+61 8 XXXX XXXX",
"address": {
"@type": "PostalAddress",
"streetAddress": "[real street address]",
"addressLocality": "Wangara",
"addressRegion": "WA",
"postalCode": "6065",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -31.79, "longitude": 115.83 },
"openingHoursSpecification": [{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "07:30", "closes": "17:00"
}],
"areaServed": ["Wangara","Landsdale","Madeley","Darch","Wanneroo","Joondalup"],
"review": [{
"@type": "Review",
"author": { "@type": "Person", "name": "[real customer]" },
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "[real review, with permission]"
}],
"aggregateRating": {
"@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "[real count]"
}
}
</script>
What would change for the real client
- Estimage — assessor quoting straight from the photo-estimate form, so the claim path on the page maps to the shop's actual workflow.
- PartsCheck — parts procurement feeding honest lead-time answers into the "how long" conversation.
- iBodyShop — shop management: bookings, courtesy car allocation, job status SMS.
- PPG colour retrieval — the spectro story on the page is their real mixing bench.
- Xero for invoicing, Podium for the review feed that replaces this page's demo copy.
- Photo upload on the form, their real licence numbers, their real before/afters shot in their own booth.
Iteration log
Pass 1 — Craft
Drove the full suite headless (Chrome + puppeteer-core): all 8 panels × 4 severities against an independently reimplemented pricing oracle, fresh-load empty submit, filled submit, toggle, FAQ, sticky bar. Found the phone field's pattern attribute threw a console error on validation — Chrome now compiles patterns with the v flag, where unescaped ( ) in a character class are illegal; escaped them. Screenshot review at 375 caught the header CTA wrapping to two lines (the recurring masthead offender) — swapped in a short "Estimate" label under 430px. Darkened the SVG booth stencil text for contrast and vertically centred the stage.
Pass 2 — Depth
The 1200×750 thumbnail preview showed only the hero — the signature was below the fold at capture, breaking the mid-demonstration rule. Restructured the hero into a two-column grid with the whole mapper as the right column: the crimson-mapped guard, chips and band now sit in the first viewport. Added the booth job-tag readout (PNL 0n · PANEL) that follows the selection, the dashed blend-zone overlays with their on-card explanation, and a one-shot sheen sweep across a freshly selected panel (skipped entirely under reduced motion). Fixed a flex-gap artefact doubling the space in the header CTA.
Pass 3 — Hardening
Final run: 136/136 checks. Verified at 375/768/1440 — masthead screenshot first at 375 (wordmark, phone icon and Estimate button on one row, no overflow); sticky call/quote bar fixed in the bottom 140px with working anchor scroll; keyboard Enter/Space drives the SVG panel zones; reduced-motion renders everything settled with zero console errors; the empty submit on a fresh load raises validation on four fields (the fifth required field — the damage description — arrives pre-filled by the mapper, which is exactly why the probe runs on a fresh navigation); honesty sweeps confirm every (08) number uses the reserved 9000 exchange, no forbidden JSON-LD types outside this guide's escaped panel, and the colophon is present. Booth-light pulse keeps a 0.78 opacity floor, so the signature is visible at any capture instant. Re-read every number on this page against the shipped model before committing.