The concept
Fallzone Play sells to local-government parks officers, school business managers, childcare directors and strata managers. Every one of them arrives with the same question — will this fit, and what does it cost — and every one of them has been quoted on equipment before anybody measured the impact area. The page's single job is to turn "what can we fit in this space" into a booking, with the fall zone drawn to scale, the tested depth named, the area in square metres and the price already on screen.
The commercial hinge is the refusal. Below about 7.2 m of clear width nothing in the range can be certified, and the page says so — in the badge, with no dollar figure, and with the impact area drawn visibly crossing the boundary on both sides. A demo that only ever says yes is a brochure.
Palette — measured, not estimated
Argued from the two surfaces councils actually buy (wet-pour EPDM and pine bark) plus the red that
marks a fall zone on every set-out drawing. Every ratio below was computed with WCAG arithmetic from
the shipped hex by contrast-playgrounds.mjs — 26 rows, 0 fail — including the cross
product of every ink against every scene fill it can land on.
The COLOUR chip needed two more fills, because a price-neutral control still has to change the drawing. Both were minted and measured with the rest: terracotta #D09A83 (6.75:1 under the body ink) and bark-natural #C6A986 (7.37:1). Forest green reuses the pinned wet-pour fill.
Service-area map labels are body-ink class with a civic-paper halo (paint-order: stroke),
never an accent — the lines-only tokens never label a map.
Type
Bricolage Grotesque 700/800 for display. Its width variation gives headings a civic confidence with no toy-like curve anywhere — this is a page a parks officer pastes into a report. Manrope 400/600 carries the body at 17px. Roboto Mono 500 has exactly one role: dimensions. Every number that is a measurement — 2.4 m FHF · 110 mm · 95 m² — is set in it, on the page and inside the drawing, so the eye learns that mono means "measured".
The typographic moment is the display cut beneath the plan: the live impact area set at clamp(4.4rem, 17vw, 9rem) with OF CERTIFIED IMPACT AREA beneath it in mono at .28em tracking. It is the argument in one number — 95 m² of ground for 30 m² of equipment.
The signature — the Zone
One SVG panel, rebuilt synchronously on every state change, holding two drawings that share a 1 m grid: a plan and a section.
The plan is view-fit to max(yard width, zone width), so the boundary is always inside
the frame — including in the refusal, where you have to be able to see the impact area cross it. The
equipment footprint is drawn to scale in steel; the impact area is its true expanded outline in the
rubber red with a drifting diagonal hatch; both axes are dimensioned; the yard boundary is a pair of
hard rules with the clear width dimensioned beneath. Where the zone overruns, the overrun is filled
with a dense red hatch on the pale overrun ground and the distance is dimensioned in metres.
The section strip beneath draws the free height of fall as a vertical dimension from the deck down to the top of the softfall, and the softfall depth to scale beneath it. That is deliberately unflattering: at the rest state 110 mm of wet-pour is a 7 px band under a 158 px fall. The thinness is the argument — that band is the only thing the standard is talking about, and its tested critical fall height is printed beside it.
No library. Plain createElementNS, laid out in real CSS pixels per width rather than a
fixed viewBox, so a 20 m yard at 375 px still renders 11 px dimension type instead of the 4 px a
fixed viewBox would give. The whole drawing is assembled synchronously and the entrance choreography
is driven from the animation loop — never by post-hoc DOM insertion, which headless Chrome has been
known to leave unpainted.
Liveness has a floor: after the entrance settles, the impact-area outline breathes between 0.62 and 1.00 stroke opacity and the hatch drifts one pattern step every two seconds. The signature is visibly alive at any capture instant, with no phase arithmetic against the seven-second thumbnail settle.
The model — integer millimetres, whole dollars
The impact-area offset comes from the AS 4685 series (following EN 1176): 1,500 mm up to 1.5 m
of free height of fall, and above that ceil(2 × FHF / 3) + 500 mm. Swings carry a
directional zone instead — 1,500 mm to the sides, 3,600 mm fore and aft. Everything is held in
millimetres and whole dollars; Number.isInteger() is asserted on every field the price
function returns, and a non-integer anywhere throws.
| Unit | Footprint | FHF | Offset | Impact zone | Area | Supply & install |
|---|---|---|---|---|---|---|
| Toddler unit, 0–5 | 4.2 × 3.0 m | 1.2 m | 1,500 mm | 7.2 × 6.0 m | 44 m² | $14,800 |
| Double swing bay | 6.0 × 2.4 m | 2.0 m | 1,500 / 3,600 | 9.0 × 9.6 m | 87 m² | $9,400 |
| Junior climber & slide | 6.8 × 4.4 m | 2.4 m | 2,100 mm | 11.0 × 8.6 m | 95 m² | $28,600 |
| Senior tower & net | 8.2 × 6.0 m | 3.2 m | 2,634 mm | 13.468 × 11.268 m | 152 m² | $46,500 |
offset = FHF <= 1500 ? 1500 : ceil(2 * FHF / 3) + 500 (swings: 1,500 sides / 3,600 ends)
zoneW = footprintW + 2 * sideOffset
zoneL = footprintL + 2 * endOffset
area_m2 = ceil(zoneW * zoneL / 1,000,000)
depth = smallest tested row whose CFH >= FHF, else NOT CERTIFIABLE (module disabled)
scope = new equipment ? module price + $1,450 inspection : $480 audit + $980 drop test
subtotal = scope + area_m2 * surface rate + access [0 | 1,850 | 2,400]
total = max(subtotal, $4,200 minimum)
The full control grid is 4 units × 29 yard widths × 4 surfaces × 3 colours × 2 scopes × 3 access options = 8,352 cells, of which 4,806 price. The $4,200 minimum binds in 156 of them. Cheapest reachable output is $4,200, which is exactly the services grid's "softfall replacement, from $4,200" floor; dearest is $93,518 (senior tower on 145 mm wet-pour over 152 m², new equipment, barrow-in). Zero non-integer cells.
The honesty clauses this page carries
Three of them are structural, not decorative.
- The page never certifies a surface. Every depth comes from a table of typical tested values, and the line "These are typical tested depths. The figure that binds is the critical fall height on your surface's own AS 4422 test certificate, and we hand you a copy of it" appears in the badge, in the ledger and in the plain-text mirror — wherever a depth does.
- No claim about injury prevention appears anywhere. The standard's language is impact attenuation, and the page uses exactly that word. A surface has a tested critical fall height; it does not have an outcome.
- The post-installation inspection is named as an independent one, carried out by someone who does not work for the installer, and the FAQ says plainly why an installer signing off their own work is worth nothing in a file.
Alongside those: the business is declared fictional on both pages, the phone number uses the
reserved (08) 9000 0405 pattern, the address is suburb-level, the ABN and
builder registration are visibly placeholder-patterned, and the live JSON-LD is
WebPage/WebSite/CreativeWork only — nothing business-shaped,
no fictional reviews marked up as structured data.
Where my oracle disagreed with the spec
The concept's numbers came from a spec-time enumeration. They were re-derived here from the prose
in an independent oracle (oracle-playgrounds.mjs, 131 assertions, 0 fail) rather than
trusted. Three disagreements surfaced. In each case the page ships the reading that reproduces the
pinned endpoints, and the disagreement is reported here rather than quietly resolved either way.
1. The smallest subtotal is $2,956, not $3,132. The concept states "the smallest subtotal is $3,132 (softfall replacement only, toddler zone 44 m², pine bark at 200 mm, open site)". That cell is arithmetically correct — but sand is $34/m² against bark's $38/m², so the true enumerated minimum is the same vector on sand: 44 × $34 + $1,460 = $2,956. It is a "smallest X" claim read off a hand-picked cell rather than produced by a sweep. Nothing downstream moves: both cells clamp to the same $4,200 minimum, so the cheapest reachable total — the endpoint that binds against the services grid floor — is unchanged. The page ships both cells and the harness asserts both.
2. The narrowest bark-versus-wet-pour gap is $3,772 today and $692 at ten years, not $4,840 / $1,760. The concept quotes those figures as the extremes "across all 408 comparable bark-vs-wet-pour vectors". They are the extremes across the 204 new-equipment vectors. On the 204 softfall-replacement vectors the $4,200 minimum clamps the bark side of the comparison and the gap narrows further — to $3,772 to lay and $692 over ten years, at toddler / softfall replacement / open access. The headline claim survives both readings and is what the page prints: bark never overtakes wet-pour; the top-ups close the gap, they do not reverse it. The on-page note is computed live from the current vector, so it is right in every cell either way.
3. The pinned one-decimal boundary display collides with the pinned "exactly to the boundary"
branch. The senior tower's impact area is 13,468 mm wide and the yard stepper moves in 500 mm
steps, so at a 13.5 m clear width there are exactly 32 mm to spare — which
toFixed(1) prints as "0.0 m", the same string the spec reserves for a true
zero. Exact zero is reachable (swing at 9.0 m, junior at 11.0 m), so both states are live
and needed distinguishing. Ruling shipped: the "exactly to the boundary" branch tests the exact
millimetre value, and a spare under 50 mm prints to two decimals — the senior at 13.5 m reads
"0.03 m of clear width to spare". No pinned string was changed; one was given a resolution the
spec did not supply.
Two smaller gaps the spec left open and this build had to rule on, recorded so they are not mistaken for oversights:
- The disabled-colour reason is per surface. The pinned string is "bark is the colour bark is.", applied to both loose-fill surfaces. It is untrue of sand, which is the other one — a reason string is a claim about every cell it covers. The pinned string ships verbatim on pine bark; sand carries the parallel "sand is the colour sand is."
- When a unit is blocked by both constraints, the yard reason wins. A module can be disabled because it doesn't fit and because no depth of the chosen surface certifies it. The boundary is the harder fact — no depth of surfacing fixes it — so it is the reason shown.
Conversion decisions
- The buyer is not a homeowner. The form asks for the council, school or organisation, and for a purchase order or quote reference; the "you are" select is written in the buyer's own vocabulary (parks or assets, business manager or facilities, centre, strata, contractor). The copy beside it promises a breakdown "laid out so it can be pasted into a council report or a board paper without being retyped", and offers to be the second of three quotes — that is the actual shape of the purchase.
- The signature sits inside the first 750 px at 1200 wide, badge and all, because the thumbnail is the commercial argument. The hero was cut back twice to get it there.
- The price lives on the artwork. A ledger below the fold does not make the capture, so the total is a real text node in a badge anchored to the drawing, with the full note and boundary templates beside it at ≥641 px and pinned short forms when it docks beneath the plan at ≤640 px.
- The set-out hands off to the form. "Send this set-out to us" pre-fills the clear width, the scope and a description of the current configuration — including, in the refusal state, an honest "nothing in the range fits, we need advice" message.
- The confirmation is local and says so. It is hidden on load and on an empty submit, shown only after a valid filled submit, and its second line states that nothing was sent, stored or transmitted. No network round-trip is faked.
Local SEO we'd implement for the real business
None of this ships on the demo — a fictional business in a real index is dishonest markup. This is
the schema we would deploy for a real Fallzone Play, with the top-level type
HomeAndConstructionBusiness, once the reviews were genuine and the address real.
{
"@context": "https://schema.org",
"@type": "HomeAndConstructionBusiness",
"@id": "https://fallzoneplay.com.au/#business",
"name": "Fallzone Play",
"description": "Playground equipment supply and installation and certified softfall surfacing for councils, schools, childcare centres and strata across Perth.",
"url": "https://fallzoneplay.com.au/",
"telephone": "+61 8 XXXX XXXX",
"email": "setout@fallzoneplay.com.au",
"image": "https://fallzoneplay.com.au/img/malaga-yard.jpg",
"priceRange": "$$",
"address": {
"@type": "PostalAddress",
"streetAddress": "Unit N, XX Example Road",
"addressLocality": "Malaga",
"addressRegion": "WA",
"postalCode": "6090",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -31.86, "longitude": 115.89 },
"openingHoursSpecification": [{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "06:30", "closes": "16:00"
}],
"areaServed": [
{ "@type": "City", "name": "Malaga" },
{ "@type": "City", "name": "Ballajura" },
{ "@type": "City", "name": "Ellenbrook" },
{ "@type": "City", "name": "Midland" },
{ "@type": "City", "name": "Guildford" },
{ "@type": "City", "name": "Bassendean" },
{ "@type": "City", "name": "Bayswater" },
{ "@type": "City", "name": "Morley" }
],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Playground and softfall services",
"itemListElement": [
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Wet-pour rubber softfall, supplied and laid" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Pine bark softfall to AS 4422" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Synthetic grass over shockpad" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Playground equipment, supplied and installed" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Independent post-installation inspection to AS 4685.0" } }
]
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9", "reviewCount": "38"
},
"review": [{
"@type": "Review",
"author": { "@type": "Person", "name": "Real verified customer name" },
"datePublished": "2026-02-11",
"reviewRating": { "@type": "Rating", "ratingValue": "5", "bestRating": "5" },
"reviewBody": "Impact-area set-out drawn over our reserve plan inside two days, and the depth table went straight into the council report."
}]
}
Beside the schema we would ship: a Google Business Profile with the Malaga yard and the eight service-area councils, a page per surface type (wet-pour / bark / synthetic grass) each carrying its own AS 4422 depth table, and one page per council named the way a parks officer searches ("playground softfall replacement, City of Bayswater").
What would change for the real client
- Their photos. Every visual here is procedural by design — no raster images anywhere. A real build keeps the Zone drawing exactly as it is and adds site photography around it; the drawing is the thing competitors can't copy from a stock library.
- Their reviews feed. The three testimonials are demo copy. Live, they would come from the Google Business Profile with the review schema turned on.
- Their systems. The enquiry would post into whatever they already run — Simpro or AroFlo for a business quoting installs and managing site works, ServiceM8 or Tradify for a smaller crew — and into Xero for the invoice. Council work adds its own: VendorPanel for quote requests, and purchase orders arriving out of TechnologyOne or Civica Authority, which is why the form asks for a PO reference rather than pretending every job starts with a phone call.
- Their certificates. The AS 4422 certificates and the post-installation inspection reports would be attached per job and served from the customer's own handover pack, so the sentence "we hand you a copy" is a link, not a promise.
Iteration log
Pass 1 — Craft
Measured every shipped token rather than trusting the spec's ratios: 26 rows, 0 fail, including both minted COLOUR-chip fills the spec did not anticipate. The secondary ink #4A5450 was minted here (7.10:1 on paper) so that no accent ever has to carry small type.
The costly find was vertical: the signature's stage opened at y = 940 at 1200 wide, with its badge at 940 — well outside the first 750 px, so the thumbnail would have shown copy and no drawing at all. Fixed by cutting the hero (padding 46/34 → 30/26, h1 ceiling 3.35 → 3.0 rem, the lede from four lines to three, the "or draw it yourself" jump link deleted) and by cutting the Zone section head from a six-line paragraph to two. Stage top now lands near 630, badge with it.
Also in this pass: the wordmark's sub-line was a nested <span> that the
.brand span rule was styling as well as the wordmark itself — the brand would have
rendered in 9 px mono. And the phone and suburb pattern attributes were written with
unescaped ( and ), which Chrome's v-flag regex rejects at
checkValidity time: the fields looked fine and validated nothing until the harness
drove a deliberately invalid value through them. Both are now escaped and both are proved by
driving, not by reading the attribute.
Pass 2 — Depth
Two z-order defects that only pixels could find. The 1 m grid was drawn under the surface fill, so the reference the whole drawing is built on was invisible everywhere it mattered; it now draws over the fills at 16 % ink opacity, the way a set-out sheet reads. And the overrun hatch lived in the boundary group, which paints after the labels — so in every does-not-fit state the surface caption lost its first two characters behind the hatch ("T-POUR 55 MM"). The overrun fills moved into the zone group and the caption is now clamped to start inside the boundary. Both states passed every DOM assert throughout.
The section strip was drawing the deck's handrail straight through its own caption. It now reserves a measured title band above the drawing, and the free-height caption and the section title each shorten by available room rather than clipping.
The second-read detail is a magnifier. At true scale 110 mm of wet-pour is a 7 px band under a 158 px fall — which is the honest picture and an unreadable one. A DETAIL ×N callout now magnifies the band beside the section, with a leader line back to it: ×3 at the rest state, ×11 on a 30 mm system. It appears only where the magnification earns its space (band under 13 px, room in the frame), and never at phone widths.
Micro-interaction: the badge's total and the display number each rise 3 px and fade in over ~0.35 s whenever their value actually changes — not on every redraw — and not at all under reduced motion. The liveness floor was tuned here too: the impact-area outline breathes between 0.62 and 1.00 and the hatch drifts one pattern step every two seconds, so there is no capture instant at which the signature looks dead.
Last: the display cut's lead sentence is state-aware, so the refusal reads "That is how far short the yard is — a 7.2 m impact area against 6.0 m of clear width" instead of claiming to surface ground it has just refused to surface.
Pass 3 — Hardening
375 px. The masthead is measured explicitly — the wordmark's right edge against the call button's left — rather than trusted to scrollWidth. The overflow probe (SVG descendants and the off-canvas skip link exempted) reports zero offenders. The badge docks beneath the artwork below 641 px and every short form is asserted from the probe, not read off a screenshot.
The widest state at the smallest width. A 20 m yard at 375 px is where a fixed viewBox would have produced 5 px dimension type. The drawing is laid out in real CSS pixels per width, and the pass asserts the minimum rendered font size in the whole scene (9.5 px) plus the presence of all four dimension labels and the section's depth and critical-fall-height captions.
The screenshot must not break the page. Entrance choreography runs on a cold-load firstDraw flag with a settle-timer backstop, and a resize renders with animation off — because a clipped puppeteer screenshot changes device metrics and fires the resize handler. The pass drives the controls, waits with nothing poking the page, and requires every animated group opaque; then repeats it after a resize to 1000 px and at DPR 2.
Rapid fire. Eight control clicks in one evaluate with no settle between them. Every handler bumps the render token before the state swap, so an in-flight entrance can never write into a rebuilt scene; the final vector, its $20,042 total and full group opacity are all asserted.
Keyboard. Chips and steppers focus and operate on Enter, FAQ summaries focus and toggle, and the global :focus-visible outline rule is proved present in the stylesheet rather than assumed. The plain-text mirror is an aria-live region and the disabled-unit reason is a role="status", so the two things a sighted user reads off the drawing are announced too.
One ornament removed. The service-area map carried a dashed hairline twin over the river band — two strokes saying one thing. One stroke says river. In the same spirit the "1 m GRID" caption now suppresses itself when the centred clear-width dimension leaves it no room, instead of crowding it.
The final copy read is a script. copy-playgrounds.mjs extracts every money,
millimetre and metre token from the rendered prose of both pages — SVG drawing labels and
the escaped schema panel excluded, since those are asserted elsewhere — and checks every one of
them against a re-derived model. Zero unexplained tokens on either page. The only allowlisted
figures are the $20m public liability cover and the "0.0 m" string the boundary ruling above
exists to avoid printing.
Totals. Independent oracle 131 assertions / 0 fail. Contrast 26 rows / 0 fail. Headless harness 235 assertions / 0 fail across both pages at 375, 1000 and 1200, plus reduced motion and DPR 2. Zero console errors on either page.