Trueline Kerbing

Build notes · Generative Assets 390

A setout sheet that prices itself

Trueline Kerbing is a fictional Forrestdale contractor extruding concrete kerb across the Perth metro. The page has one job: turn "how much to edge this" into a phone call with the metres, the profile and the crossovers already on the screen. Everything you see is drawn in the browser — SVG, CSS gradients and a little canvas-free arithmetic. There are no images on either page.

The signature

The Extrusion — a plan that zooms out around a cross-section that never changes size

The run is drawn in plan as an L: a long leg of 0.72 × the run length and a return leg of 0.28 × it. The machine crawls along the path. Behind it the kerb is a cured ribbon in the selected finish; ahead of it a survey-magenta string line runs across the prepared ground with setout pegs at every ten metres of chainage. Crossover cut-ins appear as paired end-marks with a real gap cut in the ribbon.

The frame is zoom-to-fit: its width in scene units is 0.72 × run + 4 m — 18.4 m at the twenty-metre state, 47.2 m at the rest state, 148 m at two hundred. The honest constant reference is the 2.2 m machine, drawn 2.2 m in scene units at every length, so it shrinks by a factor of eight across the stepper. At two hundred metres it is a speck on a long line, which is what two hundred metres of kerb looks like. A scale bar in the empty quadrant picks the roundest number that draws between 60 and 200 px, so it reads 2 M at the shortest run and 20 M at the longest.

The second-read detail is the corner inset. The cross-section morphs between mower strip, bullnose, roll-over, barrier and half-batter, and it holds one constant 1:10 scale at every run length — its viewBox is in millimetres and the element is pinned at 226.8 px against a 600 mm frame, which is 1:10 on a 96 dpi screen. The plan zooms from 18.4 m to 148 m around it and the section never moves a pixel. A 100 mm reference dimension is drawn beside it so the claim is checkable on screen.

How the frame is composed: the L, the empty quadrant, the badge and the constant inset $4,118 60 m of bullnose garden edge BULLNOSE · 1:10 100 mm CURED BULLNOSE STRING LINE THE EMPTY QUADRANT
The L always leaves a quadrant empty, which is where the price badge and the constant inset live. Neither overlay is allowed to touch a drawn point of the run — that rectangle test, not an aspect-ratio formula, is the binding contract.

Badge, inset and the clearance problem

The published rule for a badge painted on artwork is to compute the scene height from the badge's measured height — (badge height + margin) ÷ badge-band fraction. Applied literally here it demanded a scene roughly twice as tall as the drawing wanted, because the L's natural aspect at sixty metres is about 2.3:1 and the quadrant is already ~200 px deep. So the site ships the escape hatch instead: the binding contract is the rectangle-intersection assert — neither the badge nor the inset may cover any drawn point of the run — and the frame grows only by the amount needed to satisfy it.

Both overlays are measured, never assumed. The frame height starts at 0.28 × run + 4 m and grows if (30 px + the taller overlay + the chainage reach) ÷ scale + bottom margin + curve bulge exceeds it. The inset's horizontal position is computed from the same chainage reach, because the return leg carries its ticks and numbers on the inside face where the inset wants to sit. At ≤640 px both overlays dock beneath the plan; at ≥641 px they sit on the scene and the badge carries the full templates.

The other half of the same lesson: the pinned 2 m sheet margin is about 38 px at the twenty-metre state and about 9 px at two hundred. Every pixel-sized decoration — the worked band, the ground labels, the last chainage number, the sheet border and the corner registration marks — is therefore capped against that margin, and the top and bottom margins are computed in pixels and converted through the current scale, with 0.28 × run + 4 as the floor. The frame width stays exactly as specified.

Palette

Pale concrete, bitumen ink, survey magenta

Argued from a setout sheet lying on a hardstand. There is one loud colour and it is the only bright thing on a real kerbing job: the string line, the pegs and the chainage ticks. Every ratio below was measured from the shipped tokens with WCAG arithmetic, not estimated.

Pale concrete — page

#E5E6E1

Cured concrete read flat and cool. Held deliberately off the cream-and-terracotta default by being grey-green rather than warm.

Setout sheet

#DEDFDA

A half-step darker than the page so the white cards read as separate objects and the drawing reads as paper on a bench. Body ink 11.36:1.

Bitumen ink — body

#22262B

12.13:1 on the ground, 15.22:1 on white cards. Also the primary CTA fill under white labels at 15.22:1 (hover #14171A, 17.99:1).

Soft ink — secondary

#5A6169

5.00:1 on the ground, 6.27:1 on cards, 4.68:1 on the setout sheet. Its thinnest margin is the sheet, which is why it never carries anything smaller than the scale-bar caption.

Survey magenta — lines

#A62A6B

The string line, the pegs, the chainage ticks and the crossover marks. It also clears as body text at 5.29:1 on the ground, which is unusual for an accent this saturated.

Magenta ink / button

#8C1F58

The deeper half of the pre-minted pair: 8.56:1 white-on-fill, 8.56:1 as ink on cards, 6.83:1 on the ground, 6.39:1 on the sheet. Hover #701646, 11.10:1.

Wet concrete blue

#42627E

The metre of ribbon right behind the die that hasn't cured yet, the metro service band on the map, and the secondary CTA fill (white on it 6.40:1; as text on the ground 5.10:1).

Bitumen fill

#4A4E52

The Tonkin Highway corridor on the service map. It fails the body ink at 1.81:1, so its label is set in white (8.39:1) — and the fill is not lightened to make the ink work.

Scene fills, measured against the body ink

FillHexBody inkWhere it is
Sand#D8CFBC9.83:1bare ground, and the strip cut back behind the machine on a turf edge
Turf#8FA46B5.57:1the lawn the string line runs across
Cured grey ribbon#CFD1CB9.88:1natural-grey finish
Oxide ribbon#B98A6E5.02:1oxide colour through the mix
Exposed-aggregate ribbon#C6C3B68.61:1washed face, drawn with clipped speckle
Ribbon shadow#8C92884.77:1under the kerb face, so grey concrete does not vanish into stripped sand
Machine body#B9BDB67.98:1the 2.2 m constant reference
Old brick edge#A8705C3.72:1waiting ahead of the machine on a removal job — carries no label, by design
Bitumen#4A4E521.81:1map corridor only; labelled in white at 8.39:1

Map labels are body-ink class with a ground-coloured halo via paint-order: stroke. The one label that crosses the bitumen fill is set in white with a bitumen halo. Scene labels get the same treatment against the setout sheet.

Type

Antonio, Barlow, and DM Mono in exactly one role

Antonio 700 — display

A condensed grotesque with road-signage bones. It is the face stencilled on the hopper of a kerbing machine and on every shire standard drawing, so it earns its place rather than being chosen for drama. Set uppercase with a tight 0.98–1.02 line height.

Barlow — workhorse

A slightly squared grotesque that sits under Antonio without arguing with it. 17 px body, 16 px minimum on mobile, 1.6 line height. Every piece of prose on both pages is Barlow.

DM Mono 500 — chainage only

Used for setout strings and nothing else: 60 M · BULLNOSE · 2 X, the chainage numbers on the sheet, the eyebrows, the ledger figures. One face, one job.

The typographic moment

The rest-state total set enormous in the hero — $4,118 at up to 4.4 rem in Antonio with an 0.84 line height — and the chainage string running beneath it in DM Mono at 0.26 em tracking. The figure is measured from the running model, not typed in.

The model

Per metre for the profile, a portioned premium for the curves, a fee per crossover

Every figure below is GST-inclusive and per metre of finished kerb. The whole grid — five profiles × nineteen lengths × three curve options × three preps × the available finishes × seven crossover counts × three zones, 41,895 cells — was enumerated in an independent oracle before a line of the page was written, and the page's own arithmetic was then checked against that oracle from the running DOM.

ControlOptionRateWhat it multiplies
ProfileMower strip 100 × 75$46 / mthe full length
Bullnose garden edge 150 × 100$52 / mthe full length
Flush / roll-over driveway edge$58 / mthe full length
Barrier kerb 150 high$74 / mthe full length
Half-batter civil kerb$88 / mthe full length
CurvesStraight run+$0
Gentle curves (garden beds)+$12 / mthe curved 40% portion only
Tight radius (planter circles, islands)+$26 / mthe curved 40% portion only
PrepBare sand or a new garden+$0
Turf edge — strip and level+$9 / mthe full length
Remove an existing kerb or brick edge+$28 / mthe full length
FinishNatural grey+$0
Oxide colour through the mix+$8 / mthe full length
Exposed aggregate top+$21 / mthe full length
Crossovers0 – 6 cut-ins$85 eachthe crossover count
ZonePerth metro+$0flat, added once, outside the minimum
Outer metro (Mandurah, Two Rocks, Northam)+$220flat, added once, outside the minimum
Regionalquotedprints as "<subtotal> + travel quoted"
Length20 – 200 m in 10 m stepsa minimum run, not a charge
MinimumMinimum pour$980everything except zone travel

Three claims the oracle had to prove rather than assume

  • The curved portion is always a whole number of metres. It is 40% of a multiple of 10 m, so over all nineteen lengths it lands on 8, 12, 16 … 80 metres — zero non-integer cells across the whole grid, so no rounding rule is needed anywhere in the model.
  • The $980 minimum binds in exactly one cell. Enumerated over all 41,895 combinations, the only run whose raw figure falls under $980 is a bare twenty-metre mower strip — straight, bare sand, natural grey, no crossovers — at $920. One crossover lifts it to $1,005; gentle curves lift it to $1,016. The page says so out loud rather than hiding it.
  • The quoted-state badge never has to print "$0 + travel quoted". The cheapest computable subtotal anywhere in the model is $980, so the bare-quote case is unreachable and no bare-quote string exists.

The finish is capped by two different controls

Half-batter civil kerb disables oxide and exposed aggregate and forces natural grey — a kerb going into a road reserve is built to the shire's specified mix and finish. Tight-radius work disables exposed aggregate only and forces oxide, because you cannot wash back an exposed face on a tight radius without tearing the top. Two controls, one capped output, which is what makes the unwind partial.

StepFinishRememberedTotal
Bullnose, 60 m, straight, bare, exposed, 0 crossovers, metroexposed$4,380
Chip tight radius — exposed disabled, finish forcedoxideexposed$4,224
Chip half-batter — finish made compulsorygreyexposed (not overwritten)$5,904
Chip straight — partial unwind, exposed still invalidgrey (held)exposed$5,280
Chip bullnose — exposed valid againexposed (restored)cleared$4,380

The rule the middle row exercises: a force that makes a control compulsory does not overwrite a memory already held from an earlier force. And a restore memory is cleared by any explicit user change to the remembered control — chip natural grey while it is forced and the memory is gone, so returning to a straight bullnose leaves the finish grey rather than resurrecting exposed. Both chains are driven and asserted in the verification harness.

Worked examples, measured from the running page

ScenarioWorkingTotal
Rest state — bullnose, 60 m, gentle, turf, grey, 2 crossovers, metro60×52 + 24×12 + 60×9 + 2×85$4,118
Mower strip, 20 m, straight, bare, grey, 0, metro20×46 = 920 → minimum$980
…the same cell with one crossover920 + 85$1,005
…the same cell with gentle curves920 + 8×12$1,016
Barrier, 120 m, tight, remove, oxide, 4, outer metro8,880 + 1,248 + 3,360 + 960 + 340 + 220$15,008
Half-batter, 200 m, gentle, bare, grey, 6, metro17,600 + 960 + 510$19,070
Bullnose, 100 m, straight, bare, exposed, 0, metro5,200 + 2,100$7,300
Rest state, regional zonesubtotal 4,118 + travel quoted$4,118 + travel quoted

Grid floors, which are also the "from $X" figures in the services grid: mower strip $980 · bullnose $1,040 · roll-over $1,160 · barrier $1,480 · half-batter $1,760. The estimator's cheapest possible output anywhere is $980, which equals the grid's overall floor — the page does not argue with itself.

Conversion

Why the page is laid out this way

  • The price is inside the artwork, not only under it. The rest total prints in the hero column and on the setout-sheet badge drawn on the plan. A screenshot of the top of this page is the commercial argument, and a figure that only exists in a ledger below the fold does not make the picture.
  • The minimum is said out loud. "$980 minimum pour" sits on the sheet conditions, in the ledger and in the screen-reader mirror at all times — and when it actually binds, the badge prints the working: "20 m of mower strip computes to $920, under the $980 minimum". Trades lose jobs to minimums discovered on the invoice.
  • The estimator pre-fills the form. Profile, metres, curves, prep, finish, crossovers and zone all land in the site-details field, so the enquiry arrives warm and the caller does not have to re-describe the job. Typing over any pre-filled field marks it as yours and the estimator stops touching it.
  • Six fields, one tick. Name, mobile, suburb, metres, profile and a consent tick are required; the date and the details are optional. Anything longer and a phone user abandons; anything shorter and the callback is a guessing exercise.
  • Click-to-call twice. A tel: button in the sticky header at every width, and a fixed call/quote bar at the bottom below 861 px. Most trade traffic is a phone in one hand.
  • Four declarations ride with every quote. The minimum, the setout being in the rate, the cure times, and what happens when limestone or roots turn up. Each appears on three surfaces: the sheet-conditions strip inside the signature, the ledger notes, and the plain-text mirror. Below 641 px the strip carries the pinned short forms; the ledger and the mirror carry the full text at every width.
  • The confirmation is honest about being a demo. It is hidden on load, stays hidden on an empty submit, and appears only after a valid filled submit — no fake network round-trip, no spinner, and it says plainly that nothing was sent anywhere.

Process

Three passes, and what each one actually found

  1. Pass 1 — Craft

    A missing </script>. The closing tag was lost while the page was assembled in sections, so the whole build ran with no script block at all. Caught by extracting every script block and running node --check over it, which found nothing to check.

    The crawl looked dead to every state probe. The animation loop redrew the moving groups but only publish() wrote to window.__kerbing, so the probe's machine position was frozen at the last state change while the pixels moved. The loop now writes the position each frame.

    Chainage pegs shared a row with the ground labels. Pegs, ticks and numbers were on the outside of the L, in the same band as "CURED BULLNOSE" and "STRING LINE". Everything setout-related moved to the inside of the L; the annotations stayed in the sheet's bottom margin.

    Cured concrete disappeared into stripped sand. #CFD1CB on #D8CFBC is nearly the same value, so on a turf-edge job the laid kerb read as a hairline while the unlaid string line read bold — the argument backwards. A shadow stroke under the kerb face fixed it.

    Two ornaments removed. A run-dimension line under the long leg and an "X" text label on every crossover both collided at mid widths. The dimension went entirely (the last chainage number already carries the metreage) and the crossover became a paired end-mark with a diamond, which also stops a cut-in reading as another peg.

    Contrast re-measured from the shipped tokens. Every ratio in the palette section above was computed, not estimated. Two fills land under 4.5:1 and both are handled: the bitumen map corridor is labelled in white (8.39:1), and the old brick edge carries no label at all. The thinnest margin in the type system is soft ink on the setout sheet at 4.68:1, which is why nothing smaller than the scale-bar caption is set in it.

  2. Pass 2 — Depth

    The machine slows where the line turns. The crawl advances in cost space, not arc space: each segment costs its length times 1 + 3.4 × its turn angle. On a tight-radius run the machine visibly crawls through the planter circles and speeds up on the straights, which is what actually happens on site.

    A scale bar that changes its round number. It picks the roundest length that draws between 60 and 200 px, so it reads 2 M at twenty metres and 20 M at two hundred, with the 2.2 m machine drawn beside it at the same scale. It fills the empty quadrant with the one thing that makes the zoom legible.

    Second-read details. The metre of ribbon immediately behind the die is wet-concrete blue and has not cured. On a turf job the stripped sand appears behind the machine; on a removal job the old brick edge is drawn coursed ahead of it and gone behind. The exposed-aggregate finish is real clipped speckle in both the plan ribbon and the 1:10 section.

    Micro-interaction. The badge stamps — a 300 ms nudge on a crafted cubic-bezier — whenever the printed figure changes, so a stepper tap has a physical answer. Suppressed under reduced motion.

    Dual-speed redraw. The first draw earns a short entrance boost on the crawl (a 2.2× decaying multiplier over 900 ms, driven from the loop itself rather than by any post-hoc DOM insertion); every later state change redraws snappy, with the settled flag flipping at 620 ms on first draw and 190 ms afterwards. Chip handlers invalidate the draw token before the state swap, so a rapid-fire burst cannot leave a stale closure animating the previous run.

  3. Pass 3 — Hardening

    The 200 m state clipped its own annotation. The frame is pinned at 0.72 × run + 4 by 0.28 × run + 4, which makes the 2 m sheet margin about 38 px at twenty metres and about 9 px at two hundred. The worked band, the ground labels, the last chainage number, the sheet border and the corner registration marks were all sized in pixels and all fell outside it. Every one is now capped against the margin, and the top and bottom margins are themselves measured in pixels and converted through the current scale, with the pinned formula as the floor. The frame width is untouched.

    The inset covered the top chainage peg. Its on-scene position assumed 16 px of clearance from the return leg, but the leg carries its ticks and numbers on the inside face and they reach about 48 px. Both the horizontal position and the vertical frame growth are now computed from the same measured reach.

    375 px. Masthead checked first — the wordmark's right edge against the call button's left edge is asserted at every tested width. Business name, value proposition, price, primary CTA and a trust line all sit above the fold at 375 without scrolling, and the sticky call/quote bar carries a tel: link. The eyebrow's tracking tightens below 430 px so it stays on one line. Below 641 px the badge and the inset dock beneath the plan, the badge switches to the short run line, and the sheet conditions switch to their short forms.

    Reduced motion. No rAF loop is started at all; the machine parks at 62% of the run with the ribbon drawn to that point, the probe settles immediately, and two screenshots 1.2 s apart are byte-identical. The badge stamp and the reveal transitions are disabled in CSS and in JS.

    Form patterns proved by driving them. Modern Chrome compiles pattern as a v-flag regex, which rejects unescaped literals that older flavours accepted, and a rejected pattern validates nothing while looking fine. Each pattern is driven with a deliberately invalid value and asserted to fail checkValidity, then with a valid one and asserted to pass — reading the attribute proves nothing.

    Label-collision sweep. Screenshots inspected at native resolution at 375, 640, 641, 1000 and 1200, plus every run length and every chip. Neither overlay may cover a drawn point of the run, tested by sampling the real path vertices, the peg circles and numbers, the crossover marks and the machine in screen pixels rather than by comparing group bounding boxes — an L-shaped subject's bounding box necessarily encloses the empty quadrant the overlays live in, so the box test passes nothing useful.

    The crawl finished too early for the seven-second capture. The signature has a visibility floor by design — the machine never falls below 12% of the run, so the ribbon, the string line and the pegs are all alive at any instant. But because the crawl advances in cost space and the first straight is cheap, the original thirteen-second ramp had the machine at 85% at seven seconds: a page of finished kerb with almost no string line left to explain what the magenta is for. The ramp was measured second by second and lengthened until the settle lands the machine at 0.446 of the run — mid long leg, ribbon behind, string line and pegs ahead, which is the state the concept describes.

    The service-area map argued with its own palette. "Forrestdale yard" and "Rivervale" both crossed the bitumen Tonkin Highway corridor in body ink, which measures 1.81:1 on that fill — the exact failure the palette pins a remedy for. Rather than lighten the corridor or white out two suburb names, the labels moved off it, and the only label that genuinely sits on bitumen is the corridor's own, set in white at 8.39:1. A second pass found the map's type rendering at about 7 px on a phone (it is sized in viewBox user units, so it halves with the frame) and bumped it under a width query; every label pair is now checked for box intersection and for staying inside the map's own box at 375, 700 and 1200.

    Ornament removed. The corner registration marks were the last decorative flourish left; they stay, but shortened and capped to the margin, and the sheet keeps exactly one rule weight — the chainage tick.

Search

Local SEO we'd implement for the real business

The live page carries only WebPage, WebSite, CreativeWork and a BreadcrumbList, because Trueline Kerbing does not exist and publishing business, review or rating markup for a fictional operator would be dishonest markup in a real index. For a real contractor we would ship the block below. The top-level type is GeneralContractor — a genuine schema.org organization subtype under HomeAndConstructionBusiness — with the kerbing specialty named through additionalType, knowsAbout and hasOfferCatalog rather than invented as a type of its own.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "GeneralContractor",
  "@id": "https://truelinekerbing.com.au/#business",
  "name": "Trueline Kerbing",
  "additionalType": "https://www.wikidata.org/wiki/Q1755527",
  "description": "Machine-extruded concrete kerbing across the Perth metropolitan area: mower strips, bullnose garden edge, roll-over driveway edges, barrier kerb and half-batter civil kerb to local-government subdivision standards.",
  "url": "https://truelinekerbing.com.au/",
  "telephone": "+61 8 XXXX XXXX",
  "email": "quotes@truelinekerbing.com.au",
  "image": "https://truelinekerbing.com.au/img/extruder-forrestdale.jpg",
  "logo": "https://truelinekerbing.com.au/img/logo.png",
  "priceRange": "$$",
  "currenciesAccepted": "AUD",
  "paymentAccepted": "Cash, EFT, Card",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Unit 4, 00 Example Road",
    "addressLocality": "Forrestdale",
    "addressRegion": "WA",
    "postalCode": "6112",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": -32.155, "longitude": 115.945 },
  "openingHoursSpecification": [{
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
    "opens": "06:00", "closes": "15:00"
  }],
  "areaServed": [
    { "@type": "City", "name": "Perth" },
    { "@type": "AdministrativeArea", "name": "City of Armadale" },
    { "@type": "AdministrativeArea", "name": "City of Canning" },
    { "@type": "AdministrativeArea", "name": "City of Rockingham" },
    { "@type": "AdministrativeArea", "name": "Shire of Serpentine-Jarrahdale" }
  ],
  "knowsAbout": [
    "machine-extruded concrete kerbing",
    "mower strip and garden edging",
    "half-batter civil kerb to AS 2876",
    "crossover cut-ins",
    "exposed aggregate and oxide-coloured kerb"
  ],
  "hasOfferCatalog": {
    "@type": "OfferCatalog",
    "name": "Kerbing profiles",
    "itemListElement": [
      { "@type": "Offer",
        "itemOffered": { "@type": "Service", "name": "Mower strip and garden edging" },
        "priceSpecification": { "@type": "PriceSpecification",
          "price": 46, "priceCurrency": "AUD", "unitText": "per metre",
          "valueAddedTaxIncluded": true } },
      { "@type": "Offer",
        "itemOffered": { "@type": "Service", "name": "Bullnose garden edge" },
        "priceSpecification": { "@type": "PriceSpecification",
          "price": 52, "priceCurrency": "AUD", "unitText": "per metre",
          "valueAddedTaxIncluded": true } },
      { "@type": "Offer",
        "itemOffered": { "@type": "Service", "name": "Half-batter civil kerb" },
        "priceSpecification": { "@type": "PriceSpecification",
          "price": 88, "priceCurrency": "AUD", "unitText": "per metre",
          "valueAddedTaxIncluded": true } }
    ]
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.9", "reviewCount": "63"
  },
  "review": [{
    "@type": "Review",
    "author": { "@type": "Person", "name": "Real reviewer name" },
    "datePublished": "2026-07-14",
    "reviewRating": { "@type": "Rating", "ratingValue": "5", "bestRating": "5" },
    "reviewBody": "Forty-two metres of bullnose in a morning, curved exactly where the string said it would go."
  }]
}
</script>

The rating and review nodes are only ever emitted from a verified review feed the client actually owns — never hand-written, and never on a demonstration page. Alongside the markup we would ship a Google Business Profile with the yard's real service-area radius and the profile photos, a page per suburb only where there is genuine local content to write (a shire's standard drawing, a subdivision the crew actually worked), and the FAQ marked up as FAQPage once the answers are the client's own words rather than ours.

Handover

What would change for the real client

  • Their photographs. Every visual here is procedural because that is the point of this collection, and it proves the layout carries without stock photography. A real kerbing contractor has better material than any illustration: the before-and-after at each ten-metre peg the trust strip already promises. Those photos go into the hero, the services grid and the reviews, and the setout sheet stays as the interactive centrepiece.
  • Job costing and day sheets. AroFlo or simPRO for quoting, scheduling and job costing — the estimator's output posts straight in as a draft quote with the profile, metreage, curve portion and crossover count as separate lines, so the office is not re-typing what the customer already told the page. Tradify or ServiceM8 if the operation is smaller and the crew wants something that lives on a phone.
  • Crew and plant compliance. Assignar for the machine's prestarts, the crew's tickets and the site inductions on civil jobs, because a shire will ask for them and a subdivision principal contractor will ask for them monthly.
  • The books. Xero, with the quote-to-invoice path coming from the job-costing system rather than being keyed twice.
  • Reviews and the map pin. A Google Business Profile with the real service-area radius, and a review feed rendered from the profile rather than pasted in — at which point the review markup in the panel above becomes legitimate.
  • The setout photo folder. The trust strip promises every run photographed at chainage. That is only a promise worth making if the client can hand over a link that opens — a shared folder per job, named by address, generated when the job is closed out.
  • The estimator's rates in one place. The eleven anchors in the model live in a single object at the top of the script. For a real client they move behind a small config the office can edit without touching the page, and the "from $X" figures in the services grid are derived from the same object so the grid can never drift from the estimator.

This is a demonstration build by Sapience Analytics. Want one pointed at your customers?