Generative Assets · Industry demo guide

How the Panelcraft Fencing demo was built

Panelcraft Fencing is a fictional Butler fencing operator — Colorbond, timber and pool fencing for Perth's northern corridor estates. The page has one job: turn "three per-metre quotes that don't say what's included" into a booked measure, with the Fence Line Builder doing the persuading.

Concept

The audience is a new-estate owner on a sand block, or two neighbours staring at a leaning fence neither wants to ring about. The whole art direction is a fresh boundary line at noon — string line taut, first panels dead level — and the whole sales argument is transparency: the per-metre rate lists what's in it, and a dividing fence prints both halves so the neighbour conversation starts with numbers instead of guesses.

Palette — argued from the fence line

Block sand#EFE9DD

The levelled lot — page ground.

Monument#35393C

WA's most-ordered Colorbond colour — structure and primary ink.

Deep Ocean#39687E

The second-most — panel fills, string lines, CTAs. Line/mark only, never body text on sand.

Pale eucalypt#A8B5A0

The estate's landscaping strip — active chips, focus accents.

Eucalypt ink (derived)#44543F

Pale eucalypt fails 4.5:1 as text, so links get this derived ink — the LEARNINGS ink/line split.

Both fence colours are real Colorbond market facts, which lets the interface literally wear the product: the estimate card is Monument, the CTAs are Deep Ocean, the drawn fence is the thing being sold.

Type

  • Barlow Semi Condensed — display. The condensed capitals of a site signboard; the hero sets the trade's promise at wordmark scale.
  • Barlow — body and UI. Same family DNA, so the page reads as one voice.
  • DM Mono — metres, rates and shares. Everything with a dollar sign or a unit prints in mono, like the quote it's imitating.

The signature: Fence Line Builder

A length slider (10–60 lm), four material chips, a 0–2 gate stepper and a shared-boundary toggle drive a procedural SVG elevation. Every change clears and rebuilds the run: gates first, then panels at the material's real module (2.4 m Colorbond sheets and rail bays, 1.2 m glass panels), each panel an outer <g transform> for position with an inner <g class="p-in"> carrying the CSS build-in — the attribute/animation split the LEARNINGS SVG rules demand, so no presentation attribute is ever CSS-animated on the same element. Panel detail adapts to scale: Colorbond rib spacing and picket pitch have pixel floors so the profile stays crisp at 60 lm instead of dissolving into sub-pixel mush. Posts draw at panel joins (spigots for glass), a drafting-style dimension line prints the configuration under the run, and when the shared toggle is on, two small house glyphs — YOUR SIDE / NEIGHBOUR — sit at either end: the second-read detail that makes the 50/50 argument visual. The stagger finishes ≈1.4 s after load, so the 7-second thumbnail always captures a fully-built fence; reduced-motion renders every panel settled with no animation classes at all.

The pricing model — shape and derivation

All anchors are pinned by the wave spec; the model's shape is deliberately linear because that's how fencing is genuinely quoted — a rate per lineal metre that includes posts, rails, concrete and clean-up, plus gates priced each:

ComponentRate
Colorbond 1.8 m, standard colours$95 /lm
Hardwood picket$185 /lm
Aluminium slat$260 /lm
Semi-frameless pool glass$290 /lm
Matching gate$380 each
Pool-compliant self-closing gate (auto-selected with glass)$520 each

Formula: total = length × rate + gates × gate price. The slider's 10 lm minimum is the minimum job: 10 lm Colorbond = $950, and the services grid states the same "$950 minimum job" — the floors agree by construction, verified by assert.

The split rule: with the shared toggle on, the fence run halves under the Dividing Fences Act treatment and gates stay entirely yours: your half = fence ÷ 2 + gates. Odd-metre halves print cents (23 lm Colorbond → $1,092.50 each) rather than rounding shares that wouldn't sum to the whole job. Glass is the deliberate exception: pool barriers aren't dividing fences, so selecting glass suspends the split and the card says why — a documented flatness, not a missing feature.

Worked example (measured from the running page, not asserted from copy): the resting scenario 24 lm Colorbond + 1 gate, shared → whole job $2,660, your half + your gate $1,520, neighbour's half $1,140. The spec's ≈$1,520 hypothesis lands exactly on the model (24 × 95 ÷ 2 + 380). Harness scenarios were verified against an independently reimplemented oracle: 18 lm picket + 2 gates shared → $4,090 / $2,425 / $1,665; 30 lm glass + 1 pool gate → $9,220, all yours.

Conversion decisions

  • Above the fold at 375px: name, trade + area in the h1, call CTA, builder CTA, and three trust marks — all verified inside the first viewport by probe.
  • Header tel: + sticky mobile bar: a fencing enquiry is a phone in one hand on a sand block; the bottom bar splits Call / Get an estimate at 56 px tap height.
  • Estimator → form handoff: "Book a measure with this estimate" writes the configured scenario and both shares into the job field, sets the suburb, scrolls, and focuses the name field — the demo interaction becomes a warm lead. The form is empty at rest so validation stays honest.
  • Form fields: name, phone, suburb, job line — the four things a scheduler actually needs before a measure. Local confirmation only ("Received — thanks… we'd call you back within one business day"), clearly labelled a demonstration; no fake network round-trip.
  • The neighbour letter is surfaced three times (trust strip, reviews, FAQ) because it's the real objection: fences fail on the conversation, not the posts.

Local SEO we'd implement for the real business

This demo page ships only a WebPage schema naming it a demonstration — fictional structured data in a real index would be dishonest markup. A real Panelcraft would ship LocalBusiness + Review schema fed by their actual details and live Google reviews:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "@id": "https://panelcraftfencing.com.au/#business",
  "name": "Panelcraft Fencing",
  "description": "Colorbond, timber and pool fencing across Butler
                  and Perth's northern corridor.",
  "url": "https://panelcraftfencing.com.au",
  "telephone": "+61-8-XXXX-XXXX",
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Butler",
    "addressRegion": "WA",
    "postalCode": "6036",
    "addressCountry": "AU"
  },
  "areaServed": ["Butler","Alkimos","Eglinton","Yanchep","Jindalee",
    "Quinns Rocks","Merriwa","Ridgewood","Clarkson","Mindarie",
    "Banksia Grove","Carramar","Tapping"],
  "openingHoursSpecification": [{
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
    "opens": "07:00", "closes": "16:00"
  }],
  "priceRange": "$$",
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.9",
    "reviewCount": "87"
  },
  "review": [{
    "@type": "Review",
    "author": { "@type": "Person", "name": "(real customer)" },
    "reviewRating": { "@type": "Rating", "ratingValue": "5" },
    "reviewBody": "(pulled live from the Google Business Profile)"
  }]
}
</script>

What would change for the real client

  • Tradify — the enquiry form books straight into quoting and job cards; the estimator's scenario lands as the job description.
  • Buildxact — takeoffs for larger runs and multi-boundary estate work.
  • Xero — invoicing and progress claims wired to job completion.
  • DocuSign — the neighbour contribution letter becomes a signable agreement with both shares printed, closing the 50/50 loop digitally.
  • Stratco / supplier ordering feeds — panel and post quantities from the builder's configuration flow into supplier orders.
  • Podium + Google Business Profile — real reviews replace the demo copy and feed the schema above.

Iteration log

Pass 1 — Craft

19/19 asserts green · desktop + 375 full-page screenshots reviewed

Headless run at 1280 and 375: zero console errors, exactly one h1, resting state verified against the independent oracle ($2,660 / $1,520 / $1,140 on the card), floor consistency proven (10 lm Colorbond = $950 = the services grid's stated minimum), above-fold h1 + CTA + trust at 375, sticky call bar present with ≥44 px targets. The screenshot review — not the asserts — caught the FAQ heading orphaning "WITH" onto its own line; fixed with text-wrap:balance on section headings. Flagged the hero sun's double-circle halo as one ornament too many.

Pass 2 — Depth

29/29 asserts green · glass, slat and picket close-ups reviewed

Drove every control against the reimplemented oracle: all four material chips, slider (including keyboard arrows), stepper to both bounds (floor 0, cap 2, buttons disable), toggle off/on, and the odd-length case — 23 lm shared prints $1,092.50 halves in cents so the shares always sum to the whole job. Verified the glass exception end-to-end: split suspended, gate note and card swap to the $520 pool self-closing gate, honesty line explains the Act doesn't cover pool barriers. Prefill handoff asserted (scenario text + suburb + focus lands on the name field), FAQ driven by mouse and keyboard, drive-then-diff liveness passed. The glass close-up showed a part-drawn run — diagnosed as the capture catching the build-in stagger mid-flight, not a layout defect; the 7 s settle check later proved every panel visible. Second-read details confirmed rendering: the YOUR SIDE / NEIGHBOUR house glyphs and the glass sheen stroke.

Pass 3 — Hardening

23/23 asserts green · 375 builder, invalid/confirm states and 1200×750 thumbnail reviewed

Fresh-load empty submit flagged all four fields (aria-invalid + visible messages, probe reads invalid, focus to first error); filled submit rendered the confirmation in the contract lexicon ("Received — thanks… we'd call you back") echoing the suburb. Honesty sweeps: positive phone sweep (every (08) 9xxx number uses the 9000 exchange), a single WebPage-only JSON-LD block, exact colophon line, Index and guide links, Sapience band. Reduced-motion path renders every panel settled with zero animation classes; the 7 s thumbnail frame captures the fence fully drawn with the h1 in view. The screenshot review caught two defects every assert had sailed past: the slider's landmark labels colliding at 375 (fixed with short-form labels under 560 px) and section headings tucking under the sticky header on anchor navigation (fixed with scroll-margin-top) — and the re-shot then caught my own fix's CSS ordering bug hiding the "10 lm min" mark, fixed by moving the base rule above the media query. Chanel rule: the hero sun's halo circle was removed. Final copy read done; guide numbers re-checked against the shipped code.