Sightline Balustrades · how it was made ← Back to the site

Generative Assets · Industry demo 386

A run of fence that divides itself

Sightline Balustrades is a fictional Bibra Lake glass pool fencing and balustrade company, built for the owner who has just been told their new pool can’t be filled until the barrier is up. The page has one job: turn “how much to fence this pool” into a phone call with the panel count, the gate and the setout already on the screen. Everything on it is drawn in code — there is not one raster image on either page.

One landing page, one guide No build step, no framework SVG + vanilla JS, ~96 KB Zero console errors

The signature

The Setout

Glass fencing is priced by the panel, not by the metre, and the panel count is a ceiling division the customer can’t do in their head. That arithmetic is the whole signature. The run is drawn in true elevation and divides itself:

panels = ceil(run mm ÷ max panel width)
panel width = (run mm − (panels − 1) × 20 mm) ÷ panels

Twelve metres of frameless glass is ten panels at 1182 mm — not nine at the 1.2 m maximum plus a sliver. Every panel is cut identical, with a drawn and labelled 20 mm setout gap between them. That is why the price steps in panels rather than sliding with the metres, and why a 12 m run and a 13 m run can cost the same.

What the drawing does

  • The frame is zoom-to-fit at run + 3 m in scene units — 7 m of frame at the 4 m state, 43 m at the 40 m state. The honest constant is a 1.8 m figure standing on the coping, always drawn at 1.8 m, so it visibly shrinks as the run grows. Nothing in the model can exceed the frame.
  • The system chip changes what is drawn, not just the rate: frameless draws 12 mm panels on core-drilled spigots with no top rail; semi-frameless draws slimmer glass between square posts; aluminium draws pickets at 100 mm centres between rails; stainless wire draws horizontal wires on tensioned posts.
  • The use chip re-draws the compliance overlay. Pool barrier draws the 1200 mm effective-height line, the 100 mm ground gap and the hatched 900 mm non-climbable zone; balustrade draws the 1000 mm line and the 0.6 kN/m handrail load arrow instead. It does not change a single dollar.
  • The glass is drawn as glass — the panels carry a fill opacity so the water band and the non-climbable-zone hatch read straight through them. Panel counts up to 34 (a 40 m glass run) are drawn in full; there is no drawn cap, because that is what 40 m of glass actually looks like.
  • The order tag is drawn as a glass processor’s job tag suckered to the run. Above 640 px it sits on the sheet against the sky band and carries the full setout line; at 640 px and under it docks directly beneath the artwork with the short form, so it never covers the fence on a phone.
  • A slow surface ripple runs on the water and a specular sheen crosses the glass. Under prefers-reduced-motion both park at a settled frame, the entrance choreography completes instantly, and the drawing is identical.

Palette

A Perth pool in the afternoon

Argued from the subject, not from a mood board: pale water light on the ground, marine graphite for ink, pool aqua for every line the setout draws, and limestone bronze for the coping and the hardware. Every ratio below was measured on the shipped page from the computed colour against its resolved background — not from the palette hexes in the abstract.

Pale pool light#EAF1F2The page ground. Water light bounced off a wet coping — cool, but nowhere near white. Cards sit on it at #FFFFFF, hairlines at #D3DEE0.
Marine graphite#15252A · 13.81:1 measuredBody ink and the primary CTA fill. 13.81:1 on the ground, 15.79:1 on white cards, 15.79:1 as white labels on the button.
Pool aqua#2E8C9E · lines and marks onlyThe glass, the dimension lines, the swing arc, the water. It measures 3.43:1 as text on the ground, so it never sets type and never labels a map.
Aqua ink#1F6C7B · 5.26:1 measuredThe minted small-text twin of the aqua. 5.26:1 on the ground, 6.02:1 on cards, and 6.02:1 as white-on-fill for aqua buttons — where the raw aqua would fail at 3.92:1.
Limestone bronze#A8834E · lines and marks onlyThe coping, the spigots, the hinge stile, the latch. 3.05:1 as text — a mark colour, never a copy colour.
Bronze ink#7E5F31 · 5.89:1 measuredThe pre-minted text twin. Carries the disabled-with-reason notes and the form errors on white at 5.89:1.
Slate#3E5257 · 6.81–8.24:1 measuredSecondary copy. 7.20:1 on the ground, 8.24:1 on cards, 6.81:1 in the footer tint — the lowest ground it ever sits on.
Scene fills#C8E0E4 · #9FCBD4 · #DED5C4Glass, water, limestone paving. Measured against the body ink at 11.46:1, 9.00:1 and 10.84:1, so every scene label sits on them in the body ink — never in aqua or bronze.

Worst measured pair on the whole page: 5.26:1 — the aqua-ink eyebrow on the pool-light ground. Forty-four text pairs were sampled from the rendered page; none is below its WCAG floor. Map labels, which cross a coloured sea gradient and a drawn river, are set in the body ink with a ground-coloured halo drawn via paint-order: stroke.

Type

Three faces, three jobs

Familjen Grotesk 700 — display and the wordmark. Frameless glass sells in a Scandinavian-modern register, and this is a Swedish grotesque with enough character in the a and the g to carry a wordmark without shouting. Set tight (−0.014 em, line-height 1.06) so the hero figure reads as one object.

Instrument Sans — the workhorse. Every paragraph, label, chip and ledger line. Body is 16 px on mobile and never drops below 11.2 px anywhere on the page.

Martian Mono 500setout strings only. The dimension figures on the drawing, the eyebrows, and the one line under the hero figure: 10 × 1182 · 20 GAP. Giving the mono exactly one job is what makes it read as a drawing convention rather than a font choice. The typographic moment is that pairing — a 75 px price with a 10.6 px tracked-out mono setout string underneath it.

The numbers

The pricing model, in full

GST-inclusive, whole dollars, per installed panel. The metres choose the panel count and the panel count is what is billed — nothing on the page multiplies by metres. Every figure below was re-derived in a separate oracle script that enumerates the whole reachable control grid (3,648 cells) and checks 88 assertions; the running page was then driven through 42 randomly chosen cells and compared against it.

Systems — rate per installed panel, maximum panel width, gate rate, and the cheapest output the estimator can produce.
SystemPanel rateMax panelGateGrid floor
Frameless glass — 12 mm on core-drilled spigots$6201.2 m$980$2,480
Semi-frameless glass — between square posts$3901.2 m$720$1,560
Aluminium flat-top — pickets at 100 mm centres$2102.4 m$430$1,280
Stainless wire — tensioned 316 wire, balustrade only$3401.6 m$560$1,280
Adders, travel and the minimum. The mount adder multiplies the actual panel count and sits inside the minimum; travel is flat, added once, and sits outside it.
ControlOptionEffectScope
Fixes toConcrete slab or paving+$0per panel, inside the minimum
Timber deck — bearer packing, through-bolting+$60per panel, inside the minimum
Limestone or retaining wall — chemical anchors+$95per panel, inside the minimum
WherePerth metro+$0once, outside the minimum
Outer metro — Mandurah, Yanchep, Chidlow+$180once, outside the minimum
Regional WA — Bunbury, Albany, Geraldtonquotedbadge prints subtotal + travel quoted
Run4–40 m in 2 m steps (19 values)panel countdrives panels and the mount adder, never the gate rate
Gates0–3 (floor of 1 under a pool barrier)gate ratemultiplies the gate rate only
What it has to doPool barrier · Balustrade$0deliberately price-neutral
Minimum installApplied to panels + gates + mount$1,280before travel; binds only on aluminium and wire

Worked examples, measured from the running page

Every row was driven through the real controls in headless Chrome and read back off the state probe.
ScenarioPanelsPanel widthTotal
Rest state — frameless pool barrier, 12 m, 1 gate, concrete, metro101182 mm$7,180
Frameless, 8 m — the width recalculates71126 mm$4,340
Frameless balustrade, 4 m, no gate — the frameless floor4985 mm$2,480
Semi-frameless balustrade, 4 m, no gate4985 mm$1,560
Aluminium balustrade, 4 m, no gate — minimum binds from $42021990 mm$1,280
Aluminium balustrade, 14 m — minimum still binds from $1,26062317 mm$1,280
Aluminium balustrade, 16 m — the minimum lifts72268 mm$1,470
Stainless wire balustrade, 12 m, concrete81483 mm$2,720
Semi-frameless pool barrier, 20 m, 2 gates, timber deck, outer metro171157 mm$9,270
Frameless balustrade, 40 m, 3 gates, limestone, metro341157 mm$27,250
Rest state moved to regional WA101182 mm$7,180 + travel quoted

What the page refuses to do

  • The use chip changes nothing about the price. The glass, the spigots and the labour are identical — what changes is what may be built and whether a gate is compulsory. The page says that out loud on three surfaces rather than inventing a premium for the word “pool”.
  • Stainless wire is disabled under a pool barrier, with the reason on the page: horizontal wire gives a child a ladder. Frameless and wire are both disabled on a timber deck — a core-drilled spigot wants 100 mm of concrete under it, and a tensioned wire pulls about a kilonewton that a deck board and a coach screw won’t hold. A disabled system falls back to semi-frameless, which is valid under every use and every mount.
  • A pool barrier forces at least one gate. A run you have to climb over is not a barrier. A gate count of 0 is remembered and restored when the use goes back to balustrade — unless the customer explicitly touches the gate stepper while it is forced, which clears the memory for good.
  • Partial unwind holds. Start on wire / balustrade / concrete, switch to a pool barrier (wire disabled, semi-frameless forced, wire remembered), then to a timber deck (semi-frameless is fine, wire now doubly invalid), then back to balustrade — wire is still invalid on a deck, so the forced value holds rather than stepping through an intermediate. Only when the mount goes back to concrete does the remembered wire come back. Both constraints were driven separately in every pass.
  • Certification is not ours to sell. The page states that the pool inspection is done by the local government or a registered building surveyor, that Sightline can’t sign it off, and that it isn’t charged for.
  • Regional travel prints no number. The badge reads $7,180 + travel quoted, keeping the computable part visible wherever the total appears. The $0-subtotal case is unreachable — the cheapest computable subtotal in the whole model is $1,280.

Technique

How it is drawn

No libraries. One inline <svg> rebuilt from scratch on every state change, one requestAnimationFrame loop, roughly 700 lines of vanilla JavaScript, and CSS custom properties for the palette. No three.js, no GSAP, no canvas.

The sheet. Width comes from the container; height is solved, not assumed. The scene needs the dimension band, the paving band, 1.8 m of figure at the current scale, headroom for the panel-width callout, and then clearance for the measured height of the order tag — because the tag’s height is set in pixels while the drawing’s height falls with the viewport, which is exactly the collision that only appears at middle widths. The binding contract is a rectangle-intersection assert: the tag’s box never touches the drawn subject’s box, tested at 375, 640, 641, 900, 1000, 1100, 1200 and again at device pixel ratio 2.

The entrance. Every group is built synchronously and then faded from the animation loop itself — never by inserting nodes or toggling classes after the loop has started, which can leave groups unpainted in headless Chrome while every state assert stays green. First draw gets a 26 ms stagger capped at about a second; every subsequent state change redraws at 11 ms capped at 380 ms, so a stepper tap reads as response rather than lag.

The loop. The frame delta is clamped at zero as well as capped at 50 ms — a rAF timestamp can precede the performance.now() captured when the loop was scheduled, and a negative delta accumulated into a ripple phase produces geometry with a negative radius. The loop stops advancing while document.hidden and resumes on visibilitychange; both halves are asserted.

Token invalidation. Every control bumps a draw token in the handler, before the state swap, and the in-flight loop exits on the next frame when it sees a stale token. That is what makes a rapid-fire drive — system, use, mount, gate and eighteen run steps dispatched in one evaluate with no settle between — land on exactly 17 panels and one settled ripple rather than a stale-closure crash.

SVG discipline. Nothing is toggled through the .hidden IDL, which SVG elements do not have; visibility goes through setAttribute/removeAttribute against a [hidden]{display:none !important} guard. No element has a presentation attribute that a stylesheet rule also animates — a CSS rule silently discards the attribute, and the state stays right while the pixels go wrong.

Process

Three passes over the finished page

Pass 1 — Craft

  • The sheet was 60 % too tall. Sizing the scene by the clearance rule “(badge height + 24) ÷ 0.26” produced a 489 px sheet at 1200 px wide holding a 51 px fence — the run stranded at the bottom under an enormous block of water. Replaced with a direct solve from the measured tag height. The sheet went to 289 px and the fence from a tenth to a fifth of it. The binding contract was always the rectangle-intersection assert; the formula is only one way to satisfy it.
  • The fence looked submerged. The water ran from 42 % of the drawing height down to the ground line. Bound it to a metre figure behind the glass — 936 mm under a 1300 mm pool barrier — and added the far coping strip at the waterline, so the surface reads through the panels instead of behind and above them.
  • Two scene labels overprinted. “900 NCZ” and “1200 MIN” were both end-anchored at the right of the run, four pixels apart vertically. Split them: the zone label to the left-hand end inside its own band, the height label to the right end below its own line, and later shifted clear of the gate bay when a gate lands on the last panel.
  • The non-climbable zone was invisible. It was hatched behind opaque glass panels. Gave the panels a fill opacity so the hatch and the water read through — which is also what glass does — and moved its label into the compliance overlay so it isn’t painted over.
  • The declaration strip read as a wall. Four full paragraphs rendered as 10.3 px washed chips. Re-set as a note stack at 11.9 px with an aqua rule.
  • The ledger band had a 300 px void. A five-row card was being stretched to the height of a ten-item plain-text mirror. Moved the declaration box into the left column under the rows and set the grid to align at the start.
  • A wrong number in the trust strip. “Fourteen years out of a Bibra Lake workshop” against est. 2011 — it is fifteen.
  • Smaller: the enquiry form stacked its side copy above the fields at every width (now two columns from 900 px); service-card prices floated mid-card on the short cards (now flush to the card foot); the outer-metro note on the service-area map ran into the Cockburn label; the eyebrow wrapped mid-phrase at 375.
  • Contrast measured, not assumed. All 22 of the concept’s computed ratios reproduced exactly, and 44 pairs were then sampled from the rendered page against their resolved backgrounds. Worst measured: 5.26:1. Nothing needed re-minting.

Pass 2 — Depth

  • The setout is now drawn, not only stated. A dimensioned panel-width string sits over the first bay with leader lines and the computed millimetre figure. That is the signature’s actual argument and it was previously only ever text. It drops out below 34 px of bay width or 18 px per metre, where a dimension would be illegible anyway.
  • Second read: the glass edges are green. Every glass panel carries a faint green line down each vertical edge. Toughened glass has a green edge; you only notice it standing close to the drawing.
  • The gate was indistinguishable from a panel. Rebuilt: a two-pixel aqua-ink leaf outline, a bronze hinge stile with two hinge blocks, a dashed swing arc with an arrowhead, and the latch post carried up past the top rail to 1500 mm — which is precisely why a 1200 mm barrier needs a taller post at the gate.
  • Micro-interaction. The price lifts four pixels and settles when the setout changes, on the on-scene tag and the hero figure together, so the two read as one object. Gated on reduced-motion.
  • The sheet sky became a soft vertical gradient rather than a flat fill, and balustrade barriers now draw at 1100 mm with the 1000 mm minimum line beneath them instead of drawing exactly on the minimum.

Pass 3 — Hardening

  • Removed one ornament. The order tag printed 10 × 1182 · 20 GAP — the third appearance of the same string on one screen, after the hero and the dimension band. Cut, leaving the two lines the tag is meant to carry: the total and the setout line.
  • 375 px. The narrow sheet’s base aspect came down so the drawing isn’t marooned under empty sky, and the crowded mono callouts drop out below 24 px per metre — at that scale a 20 mm gap is under half a pixel, so the ledger carries the setout instead of eight-pixel type overprinting itself. Masthead checked first: wordmark right edge against call-button left edge, explicitly.
  • 42 grid cells driven through the real controls — randomly chosen from the reachable grid, each one setting the full control vector rather than inheriting load state — and compared against the independent oracle on panels, width, total, minimum-binding and quoted state. 42/42.
  • Keyboard. Chips and steppers take focus and operate on Enter with a visible ring; the whole estimator is drivable without a mouse.
  • Hidden-tab pause verified. The first attempt used a Chrome DevTools command this build no longer implements, and a swallowed error made a probe that never hid the page report a failure. Driving the site’s own guard directly — overriding document.hidden and firing visibilitychange — shows the ripple freezing and resuming.
  • Breakpoints and collisions. The badge dock boundary is asserted at exactly 640 (docked, short line 2) and 641 (on-scene, full line 2); the mid-width band at 900, 1000 and 1100; and device pixel ratio 2 at 1200. A label-collision sweep compares every text box in the sheet plus the badge box pairwise at all of them — zero overlaps.
  • Form. Both pattern attributes are proven by driving checkValidity on a deliberately invalid value rather than by reading the attribute; an empty submit raises validation and leaves the confirmation panel unrendered; a filled submit shows it.
  • Final tally: 239 assertions green, zero console errors on either page, zero network requests beyond Google Fonts.

Where the build and the specification differ

  • Not one pricing figure moved. Every anchor, worked example, floor, minimum-binding cell and reachability claim in the concept survived an independent reimplementation that enumerates all 3,648 reachable control cells. The panel count range 2–34, the “binds only on aluminium and wire” claim, the aluminium bind cells at 4/6/8/10/12/14 m and the wire bind cell at 4 m are all exactly right.
  • The badge clearance formula was replaced, not satisfied. Documented above — the rectangle-intersection assert is the contract and it holds at every width and pixel ratio.
  • Balustrade barriers draw at 1100 mm. The specification pins the 1000 mm height line, not the drawn top; drawing the barrier exactly on its own minimum read as a mistake.
  • Three gates on a two-bay run. Aluminium at 4 m divides into two bays, so three gates cannot sit inside the run. The extra leaf is drawn alongside the run rather than pretending it fits — the dimension string still measures the run itself, and the ledger still bills three gates.

Conversion

Why the page is shaped like this

  • The price lives inside the artwork. The order tag is on the drawing, not in a ledger below the fold, because the first screen is the entire commercial argument. At 1200 px the tag, the fence and the hero figure are all inside the first 750 px.
  • The estimator hands off to the form. Run length, the pool-or-balustrade select and the scope box arrive pre-filled with the configured setout, so the enquiry that lands is a specification rather than “how much for glass fencing”. On a real build that is the difference between a callback and a site visit.
  • Call first, quote second. A tel: button in the masthead at every width, a call button as the primary hero CTA, and a two-up sticky call/quote bar under 1024 px. Most of this traffic is a phone in one hand beside an empty pool.
  • Six form fields, not twelve. Name, phone, suburb, run length, what it has to do, roughly when, and the job. Every one of them changes the answer; nothing is collected because a CRM has a column for it.
  • Four honesty declarations on three surfaces. Beside the drawing, in the ledger, and in the plain-text mirror. The minimum, what’s in the panel rate, who certifies a barrier, and that the use doesn’t change the rate. Volunteering the limits is what a homeowner who has had three different quotes is actually testing for.
  • Disabled with a reason, never a silent bad quote. Where a system doesn’t belong on a job, the chip is disabled and the trade reason is printed. The FAQ then answers the same question at length.
  • Real standards, honestly described. AS 1926.1, AS 1288 and AS 1170.1 are real, and the 1200 mm, 100 mm, 900 mm and 1500 mm figures are the ones the standard actually uses. The business, the prices, the reviews and the phone number are not real, and the page says so.

Search

Local SEO we’d implement for the real business

This demonstration ships no business-shaped structured data — the live blocks on both pages are WebPage, WebSite, BreadcrumbList and CreativeWork only. Marking up a fictional company with a real-looking LocalBusiness and fabricated reviews would pollute the index and is exactly the sort of thing we won’t do for a client either. Below is the schema we would ship for a real Bibra Lake glass fencing business, with the reviews coming from a live feed rather than a copywriter.

The organization type is HomeAndConstructionBusiness — a real schema.org subtype of LocalBusiness. There is no “GlassFencing” type, so the specialty is carried by additionalType pointing at a Wikidata entity, plus knowsAbout and a real hasOfferCatalog. Using a made-up or enumeration-shaped token as the top-level @type is a common and quiet mistake.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "HomeAndConstructionBusiness",
  "@id": "https://sightlinebalustrades.com.au/#business",
  "name": "Sightline Balustrades",
  "additionalType": "https://www.wikidata.org/wiki/Q1129654",
  "description": "Frameless and semi-frameless glass pool fencing, aluminium
                  flat-top pool fence and stainless wire balustrade across the
                  Perth metropolitan area.",
  "url": "https://sightlinebalustrades.com.au/",
  "telephone": "+61 8 9XXX XXXX",
  "email": "setout@sightlinebalustrades.com.au",
  "image": "https://sightlinebalustrades.com.au/img/hillarys-frameless.jpg",
  "logo": "https://sightlinebalustrades.com.au/img/logo.png",
  "priceRange": "$$",
  "currenciesAccepted": "AUD",
  "foundingDate": "2011",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Unit 4, XX Discovery Drive",
    "addressLocality": "Bibra Lake",
    "addressRegion": "WA",
    "postalCode": "6163",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": -32.096, "longitude": 115.826 },
  "areaServed": [
    { "@type": "City", "name": "Perth" },
    { "@type": "AdministrativeArea", "name": "City of Cockburn" },
    { "@type": "AdministrativeArea", "name": "City of Joondalup" },
    { "@type": "AdministrativeArea", "name": "Shire of Kalamunda" }
  ],
  "knowsAbout": [
    "Frameless glass pool fencing",
    "AS 1926.1 pool barrier compliance",
    "AS 1288 glass selection and installation",
    "AS 1170.1 barrier loads",
    "Stainless wire balustrade"
  ],
  "openingHoursSpecification": [{
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
    "opens": "07:00", "closes": "16:00"
  }],
  "hasOfferCatalog": {
    "@type": "OfferCatalog",
    "name": "Glass fencing and balustrade",
    "itemListElement": [
      { "@type": "Offer",
        "itemOffered": { "@type": "Service", "name": "Frameless glass pool fencing" },
        "priceSpecification": {
          "@type": "PriceSpecification", "priceCurrency": "AUD",
          "minPrice": 2480, "valueAddedTaxIncluded": true } },
      { "@type": "Offer",
        "itemOffered": { "@type": "Service", "name": "Aluminium flat-top pool fence" },
        "priceSpecification": {
          "@type": "PriceSpecification", "priceCurrency": "AUD",
          "minPrice": 1280, "valueAddedTaxIncluded": true } },
      { "@type": "Offer",
        "itemOffered": { "@type": "Service", "name": "Stainless wire balustrade" },
        "priceSpecification": {
          "@type": "PriceSpecification", "priceCurrency": "AUD",
          "minPrice": 1280, "valueAddedTaxIncluded": true } }
    ]
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.9", "reviewCount": "148",
    "bestRating": "5", "worstRating": "1"
  },
  "review": [{
    "@type": "Review",
    "author": { "@type": "Person", "name": "<from the live review feed>" },
    "datePublished": "2026-02-11",
    "reviewRating": { "@type": "Rating", "ratingValue": "5", "bestRating": "5" },
    "reviewBody": "<verbatim from Google Business Profile — never written by us>"
  }],
  "sameAs": [
    "https://www.google.com/maps/place/?q=place_id:XXXXXXXX",
    "https://www.facebook.com/sightlinebalustrades",
    "https://www.instagram.com/sightlinebalustrades"
  ]
}
</script>

And the rest of the local work

  • Google Business Profile as the primary asset. Categories Fence contractor and Glass repair service, the Bibra Lake service area drawn to the suburbs actually run, install photos posted weekly, and a review request fired from the job-completion webhook — because aggregateRating above is only ever as honest as the feed behind it.
  • A page per system and per intent, not one page trying to rank for everything: frameless glass pool fencing, semi-frameless, aluminium flat-top, wire balustrade, and one for “pool barrier failed its inspection” — which is the highest-urgency, lowest-competition query in this trade.
  • Suburb pages only where there is real evidence to put on them — a completed job, photos, a review. Twenty thin suburb pages is a penalty waiting to happen; six with real work on them is a moat.
  • FAQPage markup on the FAQ, which is legitimate on a real site, and a Service entity per system linked back to the business @id.
  • The estimator itself is the SEO asset. “How many panels in 12 metres of glass pool fencing” is a real query, and a page that answers it with a drawing earns links from pool builders and landscapers that no amount of copy will.

For the real client

What would change on a live build

  • Their photography, alongside the drawing. The procedural elevation stays — it is the thing competitors can’t copy and the thing that turns a browser into a specification — but the hero and the system cards would carry real installs from real Perth jobs.
  • Scheduling and site measures: ServiceM8 or Tradify. The enquiry posts straight into a job with the configured setout attached, the site measure books itself, and the measure sheet comes back off the phone on site. For a larger operation, simPRO instead — its stock and assembly handling is what the flat-top and wire systems actually need.
  • The glass processor’s order portal. Toughened glass can’t be cut, drilled or ground after toughening, so the panel schedule from the site template has to reach the processor as data, not as a photograph of a notepad. That handoff is the single highest-value integration in this trade.
  • Reviews from a live feed. Google Business Profile reviews rendered on the page and marked up, with the review request triggered by job completion.
  • Xero for the quote-to-invoice run, so the estimator’s figure and the quote that follows it are the same number.
  • Analytics that answer a business question. Which system and which run length people configure before they call — that is a stock and quoting signal, not a vanity metric.
  • Their real registration, ABN, insurance and phone number in place of the placeholder patterns, and a proper LocalBusiness block once there is a real business behind it.

Built by Sapience Analytics

This is a demonstration build by Sapience Analytics.

Want one pointed at your customers? We build conversion-first sites for WA trades and technical services — every pixel drawn in code, the pricing honest, and the enquiry path as short as a phone call.