Generative Assets · Industry demonstration 381
How the Sheerline Rope Access page was made
Sheerline Rope Access is a fictional industrial rope access company working out of an Osborne Park workshop — facade and window cleaning on CBD towers, gutter and roof-line clearing where no elevated work platform will fit, sealant and remedial concrete repair, protective coating at height, and AS/NZS 5532 anchor testing for strata and facility managers. The audience is the person who signs the invoice: a strata manager with a stained north elevation, a facilities manager who needs the anchors certified before the next clean. The page has one job — turn “how much to have someone on rope here” into a phone call with the crew, the days and the drop plan already priced.
The signature — the Drop Plan
The signature is a drawn building elevation on a plan sheet. A storeys stepper grows the building floor by floor, each storey a 3.2 m band with its level number running up the left gutter in mono. A technicians stepper hangs one rope line per technician from the parapet, each with an abseiling figure at a different height, an orange descender knot and a soft shadow on the glass. A work chip changes what the ropes are doing: facade cleaning draws squeegee tracks across the glazing; gutter clearing picks the box gutter out at the roof line and hangs bagged debris on a haul rope; painting advances a coat of teal across the spandrels behind a hard colour edge; remedial repair lays a sealant bead along every joint and patches spalled panels; anchor testing pulls the ropes short at the parapet, studs it with anchor pucks and stands a pull-test gauge on it. The exclusion zone at the base widens with the crew, and a 1.8 m supervisor stands at the barrier as the sheet’s honest scale reference — he visibly shrinks as the building grows.
How it is built
Everything is one procedurally generated SVG, drawn in metres rather than pixels. The frame height in scene units is the pinned zoom-to-fit rule: storeys × 3.2 + 8 — 14.4 m at two storeys, 72 m at twenty — split into 5.4 m of sky above the parapet and 2.6 m of apron below the ground line. Each render measures the drop tag with getBoundingClientRect(), reserves its column, and solves the remaining pixel width for a scale (px per metre); the viewBox then falls out of that scale, so the 1.8 m figure and the scale bar are honest at every state. The rest state runs a slow descent loop: the figures inch down, the ropes bow, the tails trail. Every control that rebuilds scene data bumps a draw token in the handler, before the state swap, so an in-flight animation frame can never index the previous state’s array. The delta is clamped at both ends — dt = min(max(now - last, 0)/1000, 0.05) — because a rAF timestamp can precede the performance.now() that scheduled it, and a negative accumulator drives geometry negative. First draw earns a 26 ms-per-band entrance capped at 1.5 s; every later state change redraws at 11 ms capped at 520 ms, so a stepper tap reads as response, not lag.
Second read: the sheet tracks the crew. The level number each technician is currently passing re-inks from #42525F to #9C3D0E and lights a small orange tick in the gutter — and it moves down the elevation with them. Nobody notices it in the first five seconds; on the second visit it is the whole point of the drawing.
No raster images anywhere on either page. No libraries — no three.js, no GSAP, no matter-js. The elevation, the service-area map, the figures and the icons are all hand-built SVG; everything else is CSS.
Palette
Argued from a night-print rigging plan: the sheet, the chalk line, the safety orange on the ropes and the glazing teal on the glass. Every ratio below was measured with WCAG arithmetic from the shipped token, not estimated.
Service-area map labels are body-ink class, not accent: #16202B at 16.14:1 over the map paper, each with a ground-coloured halo via paint-order: stroke so a label crossing the ocean fill or the river never drops below the body-copy floor.
Type
Saira Condensed 700 carries every heading — a squared condensed grotesque argued from the stencilled level numbers painted on a building core. Public Sans does the reading: forms, ledger rows, FAQ answers, all at 16 px or better on mobile. One third face in exactly one role: Azeret Mono 500 for spec strings — the drop string under the headline figure (L08 · 3 TECH · 2 DAY), the level numbers up the gutter, the dimension and scale-bar labels, the title-block stamp, and every price anchor in the services grid. Mono is used where a real drawing would use it and nowhere else.
The typographic bravery is the headline figure: the live rest-state total set at clamp(3.1rem, 15vw, 4.9rem) with a 0.86 line height, the mono drop string tracked out at 0.28 em beneath it, and the whole thing sitting above the call button rather than below it. It is the first number a strata manager sees, and it is the number the estimator is actually computing.
The pricing model
Every figure is GST-inclusive and plausible for the Perth market. Technician rates are per technician per day. Totals display to the whole dollar — and every rate in the model is a whole dollar against a whole-unit stepper, so no reachable cell is ever fractional.
| Line | Rate | What it multiplies |
|---|---|---|
| Facade & window cleaning | $720 / tech / day | technicians × days |
| Gutter, roof-line & downpipe clearing | $760 / tech / day | technicians × days |
| Painting & protective coating at height | $880 / tech / day | technicians × days |
| Sealant & remedial concrete repair | $980 / tech / day | technicians × days |
| Anchor testing & certification | $95 / anchor, $680 min | the actual anchor count; the minimum bills instead of it, never on top |
| Drop plan, SWMS & rigging | $0 / $340 / $620 | flat, once — 2–4 / 5–12 / 13–20 storeys |
| Travel | $0 / $180 / quoted | flat, once — CBD & inner metro / greater metro / regional |
Worked examples, measured from the running page
| Scenario | Arithmetic | Displayed |
|---|---|---|
| Rest state — facade, 3 techs, 2 days, 8 storeys, CBD | 720×3×2 + 340 + 0 | $4,660 |
| Facade, 2 techs, 1 day, 3 storeys, CBD | 720×2 + 0 + 0 | $1,440 |
| Anchor testing, 5 anchors, 2 storeys, CBD | max(475, 680) | $680 |
| Anchor testing, 10 anchors, 8 storeys, CBD | 950 + 340 | $1,290 |
| Anchor testing, 25 anchors, 16 storeys, greater metro | 2,375 + 620 + 180 | $3,175 |
| Gutter, 2 techs, 2 days, 6 storeys, CBD | 760×4 + 340 | $3,380 |
| Remedial, 4 techs, 5 days, 20 storeys, greater metro | 980×20 + 620 + 180 | $20,400 |
| Painting, 3 techs, 3 days, 10 storeys, regional | 880×9 + 340 | $8,260 + travel quoted |
Locks, forces and what happens on the way back
- Never one on rope. The technicians stepper floors at two, with the reason on the control: the second technician is the rescue, not a helper.
- Height crew lock. At thirteen storeys and above the floor rises to three — two on rope, one at the top as the rescue and rope watch. A crew of two is forced to three and the two is remembered. On a partial unwind (14 → 15 storeys) the forced three holds; stepping back to twelve or below restores the two. Explicitly touching the technicians stepper while it is forced clears the memory — drive it to four at fourteen storeys, then step back to eight, and the crew stays four, not two.
- Anchor-mode lock. Anchor testing replaces the days stepper with an anchors stepper in place (days remembered and restored on return to any day-rate work) and disables the technicians stepper, forcing it to the current floor. It is a control that visibly says why it cannot change the price: the anchor rate is per anchor tested, whatever the crew — the rope watch is in the rate. The anchors value itself is never forced by anything, so it persists across mode swaps like the independent control it is.
- Regional minimum. The regional zone forces days to at least two — we don’t send a crew to Geraldton for one day — and the prior value is restored when the zone comes back to CBD or greater metro. In anchor mode the regional zone forces nothing, because there is no days stepper to force.
- Quoted state. Regional travel prints
<computable subtotal> + travel quotedeverywhere the total appears — badge, headline figure and ledger — never a bare “quoted”. The $0-subtotal case is unreachable: the cheapest computable subtotal anywhere in the model is $680.
Three declarations that are always on
- Included work. The drop plan, the SWMS, the rope logs and the exclusion-zone setup are in the day rate.
- Estimate limit. Building management charges — after-hours access, lift bookings, roof permits — are billed at cost on the invoice and are not in the estimate. That is a genuinely price-less line, and printing a number for it would be the dishonest choice.
- Minimum attendance (anchor mode only). $95 an anchor with a $680 minimum — at five anchors the minimum is what you pay. Enumerated over the whole 5–50 grid, the minimum binds at five anchors and nowhere else.
All three appear on three surfaces: the drop tag carries the pinned short forms at every width, the ledger and the plain-text accessibility mirror carry the full templates at every width. The tag carries the full crew line above 640 px and the short form below it, where it docks beneath the drawing.
Verified against an independent oracle
The model was reimplemented from the pinned anchors in a separate file that never calls the page’s own function, and the harness asserts the displayed figures against it at rest and across every worked example, force drive, partial unwind and memory-invalidation drive. Reachability claims were enumerated over the real stepper grids rather than spot-checked: both rigging tier boundaries are reachable at exactly five and thirteen storeys; the minimum-attendance binding set over the anchors grid is exactly [5]; the “1 anchor” singular is unreachable because the stepper floors at five; the cheapest output of every work type equals its services-grid floor ($1,440 / $1,520 / $1,760 / $1,960 / $680); the overall cheapest output is $680, which is the grid’s floor; and zero of the several thousand reachable cells produce a non-integer dollar. 231 assertions, all green, including one rapid-fire drive that fires three chip swaps and eight stepper clicks in a single evaluate with no settle between.
Conversion decisions
- The price comes before the button. At 375 px the fold carries the brand, the one-line value proposition naming the trade and the area, the live estimate, the call button and a trust line — in that order. A trade page that leads with a real number outperforms one that leads with a promise, and the number here is not decorative: it is what the estimator below is computing.
- Two call paths, always. A
tel:button in the masthead at every width, and a fixed call/quote bar at the bottom below 1000 px. Both tap targets clear 44 px. - The sheet leads the controls. The elevation sits at the top of the panel with the controls beneath it, so the first thing on screen is a drawing of the visitor’s own building rather than a form. It also puts the whole signature — elevation, exclusion zone, supervisor and the priced tag — inside the first 750 px at 1200 wide, which is the frame the collection captures.
- The form fields are the ones a rope-access estimator actually needs to quote without a call-back: name, phone, the building’s suburb, its storeys, the strata or building manager (optional — it decides who signs the permit and who gets the certificate of currency), a rough timeframe, and the job. The job box arrives pre-filled with the drop plan the visitor just built, so the enquiry lands warm and the lead already carries a scope. Everything typed by hand stays typed by hand — the pre-fill stops the moment the visitor edits it.
- The confirmation is honestly a demo. It is hidden on load and on an empty submit, appears only after a valid submit, summarises the job and the estimate, and says plainly that nothing was sent. The call-back promise beside the form is static copy, not the confirmation.
- The FAQ answers the objection, not the brief. The first question is rope access versus an EWP or scaffold, and the answer names the case where an EWP is the right tool — a page that admits when it isn’t the answer is a page a facilities manager believes.
Local SEO we’d implement for the real business
The live page emits only WebPage and BreadcrumbList structured data naming itself a demonstration — putting fictional LocalBusiness and Review data into a real search index would be dishonest markup. For the real Sheerline, this is the block we would ship. Schema.org has no rope-access or facade-maintenance subtype, so the top-level type is LocalBusiness and the specialty is named through additionalType, knowsAbout and hasOfferCatalog.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"@id": "https://sheerlineropeaccess.com.au/#business",
"name": "Sheerline Rope Access",
"additionalType": "https://www.wikidata.org/wiki/Q2334751",
"description": "Industrial rope access in Perth: facade and window cleaning, gutter and roof-line clearing, sealant and remedial concrete repair, protective coating at height and AS/NZS 5532 anchor testing.",
"url": "https://sheerlineropeaccess.com.au/",
"telephone": "+61 8 XXXX XXXX",
"image": "https://sheerlineropeaccess.com.au/img/crew-on-rope.jpg",
"priceRange": "$$",
"address": {
"@type": "PostalAddress",
"streetAddress": "Unit 4, XX Sarich Court",
"addressLocality": "Osborne Park",
"addressRegion": "WA",
"postalCode": "6017",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -31.9006, "longitude": 115.8100 },
"openingHoursSpecification": [{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "06:00", "closes": "16:00"
}],
"areaServed": [
{ "@type": "City", "name": "Perth" },
{ "@type": "City", "name": "Fremantle" },
{ "@type": "City", "name": "Joondalup" }
],
"knowsAbout": ["IRATA rope access","AS/NZS 5532 anchor testing","AS/NZS 1891 fall arrest","facade access","remedial concrete repair"],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Rope access services",
"itemListElement": [
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Facade & window cleaning" },
"priceSpecification": { "@type": "PriceSpecification", "price": 1440, "priceCurrency": "AUD", "valueAddedTaxIncluded": true } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Anchor testing & certification to AS/NZS 5532" },
"priceSpecification": { "@type": "PriceSpecification", "price": 680, "priceCurrency": "AUD", "valueAddedTaxIncluded": true } }
]
},
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "63" },
"review": [{
"@type": "Review",
"author": { "@type": "Person", "name": "REAL REVIEWER NAME" },
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "REAL REVIEW TEXT, synced from the Google Business Profile feed."
}]
}
</script>
The rating and review objects are only ever emitted from real, verifiable feedback — on this demonstration they would be a lie, which is exactly why they live here as a code sample and not in the page.
What would change for the real client
- Their photography. Every visual here is drawn in code, which is the collection’s point — but a real rope-access company’s best asset is a photo of a technician on a rope over St Georges Terrace. The elevation stays as the estimator; the hero gains their images.
- simPRO or AroFlo for job dispatch, rope and equipment logs and the certificate register, so the anchor certificates the page promises come out of the system that recorded the pull tests.
- HammerTech or Assignar for SWMS, inductions and competency currency — the page claims a job-specific SWMS with every drop, and that claim should be system-backed, not a Word template.
- Deputy for crew rostering, so the days on the drop plan can be checked against who is actually available before the call-back promises them.
- Xero for invoicing, with building-management charges passed through at cost as their own line — the declaration on the page is only honest if the invoice matches it.
- Google Business Profile for the review feed that would populate the
Reviewnodes above, and for the service-area definitions the map section describes. - The form posts into simPRO’s enquiry endpoint and books the call-back, with the drop-plan scope carried through as the job description.
Iteration log
Pass 1 — Craft
- A fatal shadowing bug that no page-load check could see.
var stepTechs = document.getElementById('stepTechs')andfunction stepTechs(delta)shared a name, so the element assignment overwrote the hoisted function and every technicians and days stepper click threwTypeError: stepTechs is not a function. The page rendered perfectly, priced the rest state correctly and had a live descent loop — two of its four steppers were simply dead. Forty-one driven assertions went red at once; renamed the handlersbumpTechs/bumpDays/bumpStoreys/bumpAnchors. - 375 fold overflow. The trust signal measured a bottom edge of 717 px against a 667 px viewport, so the fold carried no trust line at all. Cut the headline tail from four clauses to two, shortened the eyebrow to a single line, and tightened three vertical margins — the trust line now lands around 590 px, clear of the sticky bar.
- The quoted badge lost its space.
$5,620+ travel quoted— the leading space in the appended span collapsed in rendered text. Replaced with a non-breaking space so the quoted form reads correctly on the badge, the headline and the ledger alike. - A declaration that appeared under the wrong condition. The three-technician height reason was gated on
techs === 3rather than on the storey count, so it vanished the moment a visitor stepped the crew to four at fourteen storeys — while the accessibility mirror still printed it. Corrected the ledger to match the mirror. - Measured every shipped token: the safety orange lands at 3.51:1 as text on the ground, confirming the spec’s marks-only rule, and both pre-minted twins (#9C3D0E at 5.75:1, #AF430F at 5.78:1 under white) held without any palette shift.
Pass 2 — Depth
- The thumbnail was showing a parapet. With the controls stacked above the sheet, the 1200×750 capture caught the tag and the top storey and nothing else — the elevation, the ropes, the exclusion zone and the supervisor were all below the frame. Moved the sheet to the top of the panel and the controls beneath it; the entire signature now sits inside the first 750 px, and the estimate moved out into its own full-width band under the hero, which also fixed the mobile reading order (the ledger used to arrive before the drawing it describes).
- The badge column became a title block. Reserving the measured tag width in x left a tall empty field down the right of the sheet. Rather than shrink the drawing, that field became drafting furniture: a hairline column rule, a scale bar that re-chooses its round length per state (10 m at eight storeys, 20 m at eighteen, 5 m at two), and a three-line stamp that reads
ANCHOR REGISTERin anchor mode andISSUED FOR PRICINGotherwise. The composition now reads as a real drop plan — drawing left, title block right. - Second-read detail added: the level number each technician is passing lights orange with a tick in the gutter, and follows them down. Asserted — the lit set changes over 2.6 s of descent, and the count of lit labels never exceeds the crew.
- Micro-interactions: a 340 ms tick on both the tag total and the headline figure whenever the computed figure changes (suppressed under reduced motion), and a soft shadow cast on the glass behind every abseiling figure.
- The map argued with itself. A dashed service-radius circle implied a boundary that excluded Joondalup and Fremantle — both listed as regular runs three centimetres to its right. Replaced with an unbounded radial wash. The Swan River also ran straight through Subiaco and struck through the West Perth label; re-routed so South Perth, Applecross and Fremantle sit south of it and Subiaco, West Perth and the CBD sit north, and re-anchored five labels.
Pass 3 — Hardening
- Label-collision sweep at native resolution (asserts prove state; only pixels prove composition). Four real collisions, none of which any state assertion could see: the scale bar’s “10 m” caption overprinted the title-block stamp; the 1.8 m supervisor and his tag overran the height-dimension arrow; the “25 anchors — 10 shown” parapet label sat directly on top of two abseiling figures; and the technicians’ harness points started high enough that their heads floated above the parapet. Fixed by moving the caption above the bar, ending the drawing field after the dimension strip and clamping the exclusion zone to it, lifting the anchor label into the sky above the pull-test gauge, and starting the descent 1.35 m below the parapet so a head can never clear the roof.
- Chanel rule. Removed the five bollard ticks on the exclusion-zone barrier. The dashed line and the supervisor already say “keep out”, and the ticks crowded the one place on the sheet where the dimension arrow, the scale tag and the barrier already compete.
- Mid-width band. At 900–1100 px the two-column hero squeezed the sheet to roughly 490 px, of which the tag took 41% — the elevation came out cramped and marooned. Raised the two-column breakpoint to 1120 px so the tablet-landscape band gives the sheet the full shell width, and let the facade widen to use spare sheet rather than sit small in the middle of it.
- Patterns proved by driving. Reading a
patternattribute proves nothing — Chrome compiles them as v-flag regexes, which reject literals older flavours accepted, and a rejected pattern validates nothing while looking fine. Both patterns are driven with a deliberately invalid value and asserted to returnfalsefromcheckValidity(), and with a valid one asserted to returntrue. Every literal special inside a character class is escaped, and no ampersand survives in the manager field’s class. - 375 px, DPR 2, reduced motion and the hidden tab. Masthead wordmark measured explicitly against the call button’s left edge at all three widths; no element past the right edge with scrolling ancestors excluded; the tag docks beneath the artwork at 640 px and never intersects the elevation at any width or device pixel ratio; reduced motion parks the crew mid-drop and two screenshots 900 ms apart come back byte-identical while the page still prices the job; the rAF loop freezes when the tab is hidden and resumes when it returns.
- Final copy read. Removed a duplicated clause from the headline tail, cut “IRATA-certified crews” from the eyebrow where it repeated the trust line eight lines below, and shortened the caption under the headline figure at phone widths to a pinned short form.
Deviations from the brief, and why
- The page is light, not dark. The concept’s direction paragraph describes a white-line elevation reversed out on a dark blueprint field and calls this “a dark site”. Its own pinned palette does not:
#E6EDF2is named the page ground, cards are white, the body ink is#16202Bat 13.92:1 on that ground, and all three scene fills are pale with body-ink labels. The wave-level check agrees — “sky-glass blueprint (light, vertical elevation)”, with a different site named as the wave’s dark one. Shipped the pinned, contrast-computed palette; the reversed-out idea survives as the negative-print grid ruled across the paper. - Badge clearance solved in x, not y. The pinned rule sets the sheet’s height to
max(storeys × 3.2 + 8, (badge height + 24px) ÷ 0.22). That band is unsatisfiable for this geometry: the sky above the parapet is a fixed 5.4 m of a frame that is3.2 × storeys + 8metres tall, which is 16% of the sheet at eight storeys and 7.5% at twenty — it can never reach 22%, so forcing the height only makes a taller sheet with the same collision. Took the preamble’s stated alternative and solved it in x: the tag is measured every render, its column is reserved, and the elevation is centred in what remains. The binding contract — the badge never sits over the drawn subject — is asserted directly as a rectangle-intersection test at 375, 1000, 1200 and at device pixel ratio 2, and the y figure is still computed and published on the state probe for the record. - Anchors persist across a mode swap. The spec pins the days value as remembered-and-restored and gives the anchors stepper a default of ten, but does not say what happens to a changed anchors value when the visitor leaves anchor mode and comes back. Nothing forces or locks that control, so it behaves like every other free control and keeps its value; the days and technicians values, which are displaced by the mode, are the ones remembered and restored.
- The technicians value tracks the floor while it is disabled. In anchor mode the stepper is forced to the current floor; if the storey count then crosses thirteen, the displayed crew follows the floor to three rather than freezing at two, because the reason printed on the control is about what the building requires, not about what was selected before.