Build guide · Generative Assets
How Straightedge was made
Straightedge Line Marking is a fictional Welshpool car-park and warehouse marking operator — the wave's B2B industrial demo. The audience is strata and centre managers with a faded lot and warehouse managers facing an audit; the page has one job: a marking-quote enquiry with the bay count already computed. The signature Bay Planner draws the customer's car park bay by bay and prices it live, then hands the whole plan to the enquiry form.
Palette — argued from the asphalt and the stencil
The page is day-shift industrial: a concrete-light ground that the signature panel inverts into night-work asphalt. Yellow is paint, never prose; blue is the chalk line every marker snaps before painting.
#E9E8E4 — page ground, a broomed slab#26262A — body text at 13.0:1 on concrete#E8B325 — CTAs, hazard chevrons, the bay pulse. Marks only, never small text#3D6B9E — chalk-line rules, links, dimension strokes#2A2C30 — panel-local ground; no body copy ever sits on it#F2F3F4 — the bays themselves, panel-local#8FB4DC — panel-local setout annotation: bay numbers, dimensionsType
Archivo Black is the display face — a stencil-weight block that reads like a painted lot numeral, used for the headline, the prices and the Bay Planner's big live count. Public Sans carries everything else: a government-grade workhorse that suits a trade quoting against Australian Standards. The display moment is the bay count set huge on the asphalt, stencilled like a painted lot number, counting up as the bays draw.
The Bay Planner — signature implementation
The planner is a top-down SVG setout drawing regenerated from state on every change. A layout pass distributes bays into one or two banks of slots (accessible bays take two slots — bay plus shared area — and sit nearest the entry; stencil work draws last, the way a crew actually paints: lines first, symbols after). Each bay is two nested SVG groups: the outer <g transform> owns position, the inner group owns the CSS draw-in animation — position and animation never share an element, so no presentation attribute is silently discarded.
The draw sequence is a single rAF timeline over the bay array with token invalidation in the control handlers: every stepper/mode handler bumps the token before it swaps state, so an in-flight sequence closed over the old bay array abandons on its next frame rather than indexing a rebuilt scene — the stale-closure race class caught in Wave 25, designed out from the first draw and verified with two rapid-fire drives (ten unsettled clicks in one evaluate, twice over). Redraws are dual-speed: the first render staggers at up to 55 ms per bay (entrance choreography, 1.5 s cap), every later state change at 11 ms per bay (~520 ms cap). The safety-yellow pulse on the active bay floor is a CSS opacity animation between 0.55 and 0.95 — a never-invisible floor, so the signature is alive at any capture instant — and the whole thing renders a settled static frame under prefers-reduced-motion. State is exposed at window.__linemarking (counts, mode, every computed figure, a settled flag) so verification gates on state, never on seconds.
In re-mark mode a second-read detail appears: the faded existing lot ghosts in beneath the fresh lines at 13% opacity, slightly offset — the old paint the crew is following.
Pricing model — anchors and measured figures
Every figure below was measured from the running page and cross-checked against an independently reimplemented oracle of the pinned rates. Totals display to the whole dollar; every anchor is integer-safe.
| Item | Rate | Rule |
|---|---|---|
| Standard bay, set out & marked, two coats | $38 new layout · $26 re-mark | Mode toggle; re-mark follows the existing setout |
| Accessible bay to AS 2890.6 | $210 each | Symbol + shared-area hatching; additive above the clamp |
| EV bay stencil | $150 each | Additive above the clamp |
| Site establishment | $480 flat per visit | Setout, cones, signage — stated on every total |
| Minimum billing | 10 standard bays | Billed at the selected mode rate; note shows below 10, none at exactly 10 |
| Warehouse walkway & hatching, two-pack | $9/lineal metre | Services grid line — not in the planner |
| Bay numbering | $14/stencil | Services grid line |
| MRWA-spec / thermoplastic road works | No number | Quoted per drawing — road-authority spec work is priced on the documents (designed price-less state) |
| Scenario | Arithmetic | Measured |
|---|---|---|
| Rest state: 20 standard + 1 accessible, new layout | 480 + 760 + 210 | $1,450 |
| Same plan, re-mark | 480 + 520 + 210 | $1,210 |
| 6 standard, new, no extras (clamp binds) | 480 + 10 × 38 | $860 + note |
| 6 standard, re-mark (clamp bills at selected rate) | 480 + 10 × 26 | $740 + note |
| Exactly 10 standard, either mode | raw = clamp | no note — boundary reachable on the stepper |
| Rest state + 2 EV stencils | 1,450 + 300 | $1,750 |
The planner's cheapest outputs equal the services grid floors — new car parks from $860, re-marks from $740 — so the page never argues with itself.
Conversion decisions
- Above the fold at 375 px: name in the masthead, the trade-and-area value line as the h1, quote CTA + click-to-call, and the est.-2013 / AS 2890 trust chips — all before any scroll.
- The planner sits directly under the hero and shares the 1200×750 thumbnail frame with it: bays, hatched accessible symbol, live numeral and the $1,450 ledger all land inside the first 750 px.
- Form fields match how this trade quotes: name, business, phone, suburb, job-type chips, rough bay count. The planner's "Send this plan" button pre-fills the chips, count and a summary line — the demo interaction becomes a warmer lead.
- Mobile sticky bar with call + quote, solid ink ground (no backdrop-filter anywhere near conversion chrome). Confirmation is a designed local panel — hidden on load and on invalid submit, shown only after a valid one, and it says plainly that nothing was sent.
- Honest floors: the 10-bay minimum is stated in the meter's own unit, billed at the selected mode rate, with the note appearing only when it binds.
Local SEO we'd implement for the real business
This demo page carries only WebPage/CreativeWork schema naming it a demonstration — fictional structured data in a real index would be dishonest markup. For a real client we'd ship LocalBusiness schema wired to their actual details and live review feed:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Straightedge Line Marking",
"description": "Car-park and warehouse line marking across the Perth
metropolitan area — bay layout and re-marking to AS 2890, accessible
bays to AS 2890.6, EV stencils and warehouse walkways.",
"telephone": "+61 8 9000 0304",
"url": "https://www.example-straightedge.com.au",
"address": {
"@type": "PostalAddress",
"addressLocality": "Welshpool",
"addressRegion": "WA",
"postalCode": "6106",
"addressCountry": "AU"
},
"areaServed": "Perth metropolitan area",
"openingHoursSpecification": {
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "07:00", "closes": "16:00"
},
"priceRange": "$$",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9",
"reviewCount": "87"
}
}
</script>
Type note: schema.org's LocalBusiness hierarchy has no line-marking subtype — the nearest branches (HomeAndConstructionBusiness and its children) don't honestly describe pavement marking — so the correct would-ship top-level @type is the parent LocalBusiness itself, not a borrowed trade subtype or a specialty enumeration token.
Iteration log
Pass 1 — Craft
The first 1200×750 render failed the thumbnail read: the hero ran 343 px tall and the planner columns were stretch-aligned, so the panel grew to match the controls card and pushed the big numeral to y≈886 — copy without a signature. Compacted the hero (two-line headline, trimmed lede), switched the planner grid to start alignment, visually hid the controls heading and tightened the card. Measured after: strip bottom 645, numeral top 671, ledger total top 692 — the whole rest state inside the frame.
Screenshot review also caught the shared-area hatch drawn in safety yellow over the safety-yellow pulse — invisible precisely when the pulse parks on the accessible bay, which is the rest state. Hatch is now thermoplastic white (also what a crew actually lays). Fixed a dead setout-length expression to max(bank units) × 2.6 m.
Pass 2 — Depth
Added the re-mark ghost: toggling to re-mark fades the existing lot in beneath the fresh lines (13% opacity, 1.6 px offset) so the mode change reads as a story, not a price switch. Drove every control against an independent oracle of the pinned rates: rest $1,450, re-mark $1,210, clamp $860/$740 with note at 6 bays and silence at exactly 10, rest + 2 EV $1,750 — plus two rapid-fire volleys (ten unsettled clicks in one evaluate) to prove the token-invalidation holds; final states matched the oracle to the dollar with zero console errors.
Pass 3 — Hardening
Masthead first at 375: wordmark right edge vs call-chip left edge measured with no collision, and the icon-only chip gained an aria-label. Sticky call/quote bar verified fixed in the bottom 140 px with 48 px targets; empty submit after a hard reload raises native validation with the confirmation panel still hidden; the phone pattern is v-flag-safe. Reduced-motion renders the settled frame instantly with the pulse static at 0.7. Chanel rule: removed the dashed aisle centreline — car parks don't mark one, so the drawing is more honest without it — and a dead header element.
What changes for the real client
Their photography where the procedural asphalt panel now stands (though the planner stays — it earns the enquiry), a live Google Business Profile review feed instead of demo copy, real ABN/registration numbers, and quoting wired into their job system — for WA marking crews that's typically AroFlo, Simpro, ServiceM8 or Tradify, with invoicing through Xero. The Bay Planner's plan payload would post straight into the job record so the estimator's counts arrive as line items, and MRWA prequalification documents would get their own indexed page.