Crewline Labour Hire — how this demo was built
Site 344 in the Generative Assets collection, Wave 37 (Industry Demos XXVI). A construction and civil labour-hire landing page for Perth, built as a B2B conversion page around one signature: the Crew Board.
Concept
Crewline Labour Hire is a fictional Welshpool labour-hire company supplying labourers, trades assistants, ticketed operators, qualified trades and leading hands to Perth builders, civil contractors and site managers — "ticketed crews, on site by seven". The audience is the site manager who lost two labourers on Friday, the civil contractor staffing a three-week pour, the shopfitter needing a TA for a fortnight. The page has one job: a crew request with head-count, roles, shift and days already priced, so the phone call is a confirmation rather than a negotiation.
Art direction is the site gate at 6:45am — slab-grey ground, bitumen ink, hi-vis orange, galvanised-steel linework — deliberately blunt and tabular, "a whiteboard at the site office with the crew written up". Every visual is procedural: the site scene, the crew figures, the whiteboard, the metro map are all SVG and CSS. No raster images.
Palette — measured, not assumed
Contrast ratios were measured from the shipped hex tokens with WCAG relative-luminance arithmetic in Pass 1 (a small Node script), not read off the spec. The spec's hypotheses held: bitumen labels on the base hi-vis orange measure 5.43:1, so the pre-minted deeper fill #D95A12 (4.27:1 with bitumen labels — worse, because the label is dark) was not needed and the base orange ships on every button. Orange copy on the ground fails by design (2.62:1) and never appears — every accent-coloured word uses orange-ink #A8420A.
- Slab
- Bitumen
- Hi-vis
- Orange-ink
- Galvanised steel
- Steel-ink
- Whiteboard
Hi-vis on bitumen (the ledger's total, the sticky-bar call button) measures 5.43:1 — the same pair reversed. Light steel #C9CDD2 on bitumen (ledger sub-lines) measures 10.34:1.
Type
Barlow Condensed 700 for display, headings, the whiteboard and every number — the site-signage condensed that reads through a windscreen. Barlow 400/500/600 for body and controls. Scale is deliberate: hero h1 at clamp(2.55rem → 4rem), the display moment "FIVE ON SITE BY SEVEN, ALL WEEK" at clamp(2.2rem → 4rem) in condensed caps with the head-count word in orange-ink, section h2s at ~2–3.1rem, body 17px, mobile body never below 16px. The bravery is the live display line: the number word and the day phrase are rewritten by the board ("Twenty-one on site by seven, for four weeks"; "No one on site by seven, yet — add a crew").
The Crew Board
Techniques
Inline SVG (viewBox 720×440) for the site scene: slab in false perspective with a timber formwork edge and orange pegs, a site office with a CREWLINE sign, a crane jib with a swinging hook, a site gate with a mesh pattern fill, a forklift and a ute as toggled props. Crew figures are built at runtime with createElementNS — head, hard hat, vest with two reflective stripes, arms, legs, shadow — with role variants: a tool belt for TAs, an orange hat stripe for qualified trades, a white hat and clipboard for the leading hand, a forklift drawn beside operators. Each figure is TWO nested groups: an outer <g transform="translate()"> for slab position and an inner .fig group that CSS scales up from its feet — the W16/W17 rule that a CSS transform must never share an element with an SVG transform attribute. Figures fill 24 slots (4 rows × 6) front row first, so the first heads land at the formwork edge where the eye is.
The whiteboard is HTML laid over the artwork by CSS grid (grid-area:1/1 on both the SVG and the board) so the panel grows to whichever is taller; from 640px up it hangs at the top-left of the scene, below 640px it stacks under the scene and the SVG's viewBox is cropped by JS to the right-hand 444 units so the slab fills the phone width. The price badge is a two-line block on the board: line 1 the job total ("$11,920 · JOB TOTAL"), line 2 "= $2,384 a day". Zero heads with the leading hand off is a designed price-less state: the badge reads "add a crew to price it", line 2 is removed (not blanked), the board reads "— on site by seven", the ledger prints no dollar figure — never $0.
Dual-speed redraw (W21): the first draw staggers figures at 70 ms (1.5 s cap), every later change at 16 ms (500 ms cap). Every control handler bumps a drawToken BEFORE the state swap; the pop-in class and the settled timer both check the token, so a rapid-fire drive (labourers 0→8, shift 10, days 20 in one evaluate) settles at $92,800 with exactly eight figures and no in-flight residue. The crane hook swings by rAF with dt = min(max(now − last, 0)/1000, .05), amplitude 5.5° + 1.2° harmonic, always fully opaque (a never-invisible floor), pauses on document.hidden, and parks at 3° under reduced motion where the figures also appear without transition. Probe: window.__labourhire carries state, total, perDay, heads, priceless, note and settled.
Pricing model (per worker-hour, GST inclusive; super, workers' comp, insurances and PPE included)
| Line | Rate | Notes |
|---|---|---|
| General labourer | $58/hr | Stepper 0–8. Four-hour minimum per worker per day → cheapest priced output $232 = the grid floor. |
| Trades assistant | $66/hr | Stepper 0–4. Tool-belt figure. |
| Ticketed operator | $78/hr | Stepper 0–4. Forklift drawn beside the crew while ≥1. |
| Qualified tradesperson | $92/hr | Stepper 0–4. Hat-stripe figure. |
| Leading hand (toggle) | $110/hr | One more head on the board; live at every combination. Clipboard figure. |
| Shift chips | 4 · 8 · 10 hr | 4 hr is the minimum call, stated on the chip and on-card. Rest 8 hr. |
| Days | 1–20 | Multiplies the crew hours AND the vehicle line. ≥10 days → NOTE only ("ten days and up: ask about our project rate"), no price change, no disable. Boundary: 9 no note, 10 note — both asserted. |
| Site vehicle & tools (toggle) | +$95/day | Ute with the crew's tools and a fuel card, × days. Live at every combination; drawn at the gate. With no crew on the board it stays priceless ("the ute comes with the crew"). |
| Regional / FIFO / night / weekend | no number | "Quoted per site — award penalties applied as they fall." Designed price-less line on the grid, the ledger inclusion note and the FAQ. |
Job total = (Σ heads × rate + 110 if leading hand) × shift hours × days + 95 × days if vehicle. Line 2 = total ÷ days — integer by construction because every line is per-day × days; totals display to the whole dollar.
Worked examples — measured from the running page against an independent oracle
| Scenario (full control vector set explicitly) | Spec | Measured | Line 2 / notes |
|---|---|---|---|
| Rest: 4 lab + 1 TA, 8 hr, 5 days, LH off, ute off | $11,920 | $11,920 | = $2,384 a day · five figures · no note |
| 2 operators only, 10 hr, 1 day | $1,560 | $1,560 | = $1,560 a day · forklift drawn |
| 1 tradesperson, 4 hr, 1 day | $368 | $368 | = $368 a day |
| Rest + leading hand | $16,320 | $16,320 | = $3,264 a day · six figures |
| Rest + vehicle | $12,395 | $12,395 | = $2,479 a day · ute at the gate |
| Rest at 10 days | $23,840 | $23,840 | = $2,384 a day · project-rate NOTE on board, ledger and a11y mirror |
| Rest at 9 days | $21,456 | $21,456 | = $2,384 a day · no note anywhere |
| All steppers 0, LH off (± vehicle) | price-less | price-less | "add a crew to price it" · line 2 absent · no "$0" in badge, board, ledger or mirror · zero figures, no ute |
| Leading hand alone, 4 hr, 1 day | $440 | $440 | = $440 a day · one clipboard figure |
| Rapid-fire: lab 0→8, shift 10, days 20 in one evaluate | $92,800 | $92,800 | = $4,640 a day · settled, 8/8 figures in |
| Cheapest priced: 1 labourer, 4 hr, 1 day | $232 | $232 | = grid floor "from $58/hr — $232 a call" |
| Full board: 8+4+4+4 + LH, 10 hr, 20 days, ute | oracle | $305,500 | = $15,275 a day · 21 figures, all 24-slot rows used, note on |
Conversion decisions
- Above the fold at 375: wordmark, "Construction & civil labour hire across Perth — ticketed crews, on site by seven", Request a crew + Call buttons, and the trust line (white card verified · same-day swap · super and comp in the rate) all inside the first 812px; the scene follows.
- Click-to-call everywhere: header phone with the "· before 9pm" cue at desktop, an icon-only 44px button at 375 to keep the masthead in one row, and a mobile sticky bar whose call button carries the after-hours line: "Call before 9pm — crew short for tomorrow?". The same line repeats as a dark pill under the hero and inside the confirmation panel, because that is the moment a labour-hire phone actually rings.
- Request form fields: company (B2B — the invoice goes to an entity), name, phone, site suburb, start date, an optional induction/start-time field, and the crew request textarea pre-filled from the board (W12 handoff: crew, shift, days, ute, estimate, "project rate please" from ten days). Pre-fill stops the moment the user edits the textarea. Front-end validation only; visible focus rings; a designed confirmation panel hidden until a valid filled submit — it echoes the head-count, total and per-day figure and the after-hours line. Nothing is sent and no round-trip is faked.
- Rates grid = the board's anchors: six cards, the labourer card carrying the "$232 a call" floor that equals the board's cheapest priced output; the sixth card is the honest price-less line for regional/FIFO/night crews.
- Trust strip: est. 2012, placeholder ABN, RCSA membership, $20M public liability + workers' comp, tickets verified, same-day swap — all demo copy on a page declared fictional.
- Reviews: three, written as site managers talk (a Friday-night call staffed by Monday in Cockburn, the Osborne Park fit-out TA kept eleven weeks, the Baldivis builder who books the same four every slab). Not marked up as review schema.
- Service area: a procedural SVG metro map — coast, hatched metro shading, the Swan, eleven named suburbs and the Welshpool star — with "regional by arrangement" noted in the map and the copy.
- FAQ: the five questions the trade actually gets: how fast (honest: labourers same-day before 9pm, tickets and trades usually next day), what's in the rate, who supervises, what if they don't suit, weekends/regional/FIFO.
Local SEO we'd implement for the real business
The live page emits only WebPage / WebSite / BreadcrumbList schema naming it a demonstration — fictional business data must not enter a real index. For a real labour-hire client the page would carry this (values illustrative):
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "EmploymentAgency",
"@id": "https://www.example-labourhire.com.au/#org",
"name": "Crewline Labour Hire",
"description": "Construction and civil labour hire across Perth — labourers, trades assistants, ticketed operators, qualified trades and leading hands.",
"url": "https://www.example-labourhire.com.au/",
"telephone": "+61 8 9000 0344",
"email": "crews@example-labourhire.com.au",
"address": {
"@type": "PostalAddress",
"streetAddress": "Unit 0, 0 Example Road",
"addressLocality": "Welshpool",
"addressRegion": "WA",
"postalCode": "6106",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -31.99, "longitude": 115.94 },
"areaServed": [
{ "@type": "City", "name": "Perth" },
{ "@type": "AdministrativeArea", "name": "Perth metropolitan area" }
],
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"], "opens": "05:30", "closes": "21:00" }
],
"priceRange": "$$",
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Labour hire charge-out rates",
"itemListElement": [
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "General labourers" }, "priceSpecification": { "@type": "UnitPriceSpecification", "price": "58", "priceCurrency": "AUD", "unitText": "worker-hour" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Ticketed operators" }, "priceSpecification": { "@type": "UnitPriceSpecification", "price": "78", "priceCurrency": "AUD", "unitText": "worker-hour" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Qualified trades" }, "priceSpecification": { "@type": "UnitPriceSpecification", "price": "92", "priceCurrency": "AUD", "unitText": "worker-hour" } }
]
},
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "63" },
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "Client name (from the review feed)" },
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "Six through the gate at 6:50 Monday after a Friday-night call."
}
],
"sameAs": [ "https://www.google.com/maps/place/…", "https://www.linkedin.com/company/…" ]
}
</script>
Alongside: a Google Business Profile category "Labour hire agency" with the depot pin, suburb-level service pages for the corridors the crews actually run (Kewdale/Welshpool industrial, Osborne Park, Wangara, Cockburn), a review feed pulled from Google, and the FAQ marked up as FAQPage only when the answers are the client's real ones.
What changes for the real client
- The board becomes a live request: the crew request posts to their labour-hire platform — Entire OnHire or FastTrack360 — as a job order with roles, head-count, shift and dates, so allocations see it in the same screen they roster from. Charge-out rates come from the platform's rate cards (per client, per award), not from constants in the page.
- Rostering: if they run Deputy for shifts and timesheets, the request creates the shift shells and the "names and ticket numbers the night before" email is generated from the roster, not typed.
- Accounts: weekly invoicing off signed timesheets flows to Xero; the "one invoice a week" promise on the page is then a system fact.
- Their photos, their crews, their reviews: the drawn scene stays as the brand's illustration style or gives way to site photography; reviews come from the Google feed; the trust strip carries the real ABN, labour-hire licence number and insurer's certificate of currency.
- Compliance surface: a ticket-verification statement linked to their actual process (white card, HRW licence checks, VOC records) — the thing that wins a tier-one contractor's approved-supplier form.
Iteration log
Pass 1 — Craft
- Measured every palette pair (table above). Base hi-vis with bitumen labels held at 5.43:1 → deeper fill unused; orange-ink used for every accent word; steel demoted to lines with steel-ink for captions.
- First render put the whiteboard in a side column beside a squat scene — figures rendered tiny and the art sat too far down the hero. Recomposed: the whiteboard now overlays the top-left of the scene (grid-area stacking), the scene was redrawn with the office, slab, crane and gate composed to the right of the board's footprint, and the hero h1 was capped at 4rem so the art rises into the first 750px at 1200 (measured: art top ~270px, badge bottom ~535px).
- Fixed a W16-class defect before it shipped: figures originally carried both a
transformattribute and a CSStransform— split into an outer position group and an inner animated group. - Screenshot review of the service-area map caught Fremantle sitting in the ocean and a metro-shading polygon that didn't follow the coast — the coastline was redrawn as a straight-segment path, the metro shading re-cut to it, the Swan re-anchored at the new mouth.
- Copy read: the eyebrow shortened to "The Crew Board — price it first" so it holds one line at 375; panel heading allowed to wrap its rate caption.
Pass 2 — Depth
- Role variants on the figures (tool belt, hat stripe, clipboard, forklift companion) so the board reads at a glance; the ute appears at the gate when the vehicle toggle is on and never while the board is price-less.
- Second-read detail: the whiteboard's day range rewrites itself ("Mon → Fri", "12 days · 2 wk + 2 days"), and the display line rewrites the head-count word and the day phrase (all week / for two weeks / for four weeks).
- Mobile viewBox crop: below 640px the SVG shows only the right-hand 444 units so the slab and crew fill the phone width instead of leaving the board's desktop footprint empty.
- Micro-interaction: the hook's swing is a two-harmonic sine (5.5° + 1.2°) so it never reads as a metronome; steppers disable at 0/1 and at their maxima; shift chips carry radio semantics.
Pass 3 — Hardening
- 375: masthead measured (wordmark right edge clear of the icon-only call button; CTA inside 375); no horizontal overflow on either page; sticky call bar in the bottom 140px; badge tight variant below 640 and the badge never overlaps the scene's box at 375.
- Harness (141 asserts, headless Chrome): every worked example with the full control vector set explicitly, both note boundaries (9/10 days), the price-less state with explicit line-2 ABSENCE and no "$0" anywhere, the $92,800 rapid-fire plus a second rapid-fire over toggles and chips, stepper clamps, keyboard Enter on a stepper, drive-then-hash liveness, empty submit (5 invalid fields, panel stays hidden) and filled submit (panel shown, echoes $11,920), reserved-phone sweep, JSON-LD allowlist on both pages, guide panel presence, zero console errors.
- Reduced motion: hook parks at 3°, figures appear without transition, hero rise disabled. rAF paused when the tab is hidden. No
backdrop-filter; header and sticky bar are solid. - Chanel rule: removed the decorative fence-line group left in the scene's first draft; the crane jib's hatching stays because it reads as structure.