Generative Assets · Industry demonstration 403
How the Halfcell page was made
A fictional Henderson corrosion-protection contractor, one landing page, and a signature that draws the only number in the trade a page can honestly compute — how many kilograms of anode a structure needs.
The concept
Halfcell Cathodic Protection designs, supplies and installs sacrificial anodes for marine and buried steel around Cockburn Sound, and measures the potentials afterwards. The audience is a marina operator whose piles are twenty-two years old, a Henderson fabricator who needs a stamped AS 2832.3 design attached to a tender, and a Kwinana plant engineer with a buried intake line. The page has one job: turn “how much anode does this need?” into a booking, with the current demand, the charge, the mass, the count and the price already on the screen — and with the refusal no competitor’s calculator will give them.
The honesty clause this site was built around. Anode mass is arithmetic. The steel’s remaining life is not. So the page never promises a service life for the structure: it sizes anodes to a design life at a stated mean current density, names the −800 mV criterion as the standard’s rather than ours, and prints one sentence wherever the design life appears — “we size the anodes and we measure the potential. What the steel has left is a thickness survey, not a calculator.” The baseline potential survey is the measurement, and it is a priced line on every estimate.
Conversion decisions
- The price is in the hero and on the drawing. A visitor at 1200×750 sees the live installed total twice before scrolling: as a Fraunces figure in the hero card, and stamped on the section in the badge. The signature is 715 px tall, so printing the total only at its foot would have put the commercial argument below the fold.
- The calculator is the page. There is no separate “pricing” section — the section drawing, the ledger and the display moment are three views of one state. The services grid below exists to anchor the rates the ledger uses, not to duplicate them.
- The refusal sits inside the estimator, not in the FAQ. Selecting fresh water disables every alloy and every zone, prints no dollar figure anywhere it would normally print one, and explains the electrochemistry in the ledger. It is the strongest sales moment on the page and it is a lost sale.
- Form fields chosen for the trade. Name, phone, suburb-or-berth, structure type, and — deliberately its own required field — the water it sits in, with a hint telling the visitor to answer honestly because it changes our answer. A real intake for this trade lives or dies on that one field.
- Sticky bar copy in the trade’s voice. “Call the shed” and “Get a design”. It owns a
tel:link and an in-page anchor to the quote form, with 48 px targets; the conversion contract is semantic, not vocabulary.
Palette
Argued from what the job actually looks like: Cockburn Sound water, a fresh zinc anode, corroded steel, and the magenta of a plotted potential trace. Every ratio below was measured from the shipped tokens with WCAG arithmetic during Pass 1 — 39 pairs, including every scene fill against the ink that labels it.
#EDF1EFPage ground. Cool grey-green, not cream — this is water, not parchment.#111C1A15.3:1 on paper, 17.43:1 on cards. Body, labels and the primary CTA fill.#0B55667.36:1 on paper, 8.38:1 on cards. Water, wetted-area hatch, eyebrows.#8A3E706.14:1 on paper, 6.99:1 on cards. Draws exactly one thing.#B9D3D611.08:1 against the ink that labels it.#D6E2E113.13:1. Splash and tidal bands, imported trench backfill.#C7C0AE9.61:1. Seabed band and native soil.#AEB6B88.45:1. Piles, sheet pans, tank shell.#CFD5D811.75:1. The sacrificial block, lighter than the steel it protects.#B07A4E4.76:1. Appears only on bare steel, only in the tidal band.The most constrained colour on the page
The potential magenta fails 4.5:1 on four of the six scene fills — seawater 4.45, seabed 3.86, steel 3.39, corrosion 1.91. So it is forbidden as text on all four and it draws one line: the half-cell potential scale, its ticks, its open-circuit marker and the criterion. The marine teal is forbidden on steel (4.06) and corrosion (2.29) for the same reason. Every zone and component label in the drawing is the deep ink, with a ground-coloured halo wherever it crosses a fill.
| Ink | Paper | Card | Seawater | Splash | Seabed | Steel | Anode | Corrosion |
|---|---|---|---|---|---|---|---|---|
Deep ink #111C1A | 15.30 | 17.43 | 11.08 | 13.13 | 9.61 | 8.45 | 11.75 | 4.76 |
Marine teal #0B5566 | 7.36 | 8.38 | 5.33 | 6.32 | 4.62 | 4.06 × | 5.65 | 2.29 × |
Potential magenta #8A3E70 | 6.14 | 6.99 | 4.45 × | 5.27 | 3.86 × | 3.39 × | 4.72 | 1.91 × |
White on the three button fills measures 17.43 (ink), 8.38 (teal) and 6.99 (magenta); the hover states measure 19.74, 11.00 and 9.35. The quiet ink #4A5A57 carries secondary copy at 6.37 on paper and 7.26 on cards. The quote form and the trust strip sit on the deep ink, so their copy was measured against it too: the lede #D5DEDC at 12.71, field labels #AEBDBA at 8.95, the field hint #93A5A1 at 6.75, and the validation ink #F3C0DF at 11.14.
Type
Fraunces 600 is the only serif in its wave, and it is argued rather than decorative: the deliverable a cathodic-protection client actually buys is a signed report, and a report has a serif on its cover. Its optical axis lets the display moment — 301 kg at 136 px — hold a heavy, slightly editorial weight without turning into a logo, and the same face sets the h1, the section heads, the installed total and the pull quote, so the price reads as a conclusion rather than a widget.
Public Sans 400/600 is the workhorse: body copy, every control, every ledger row, every label in the drawing. It carries tabular figures, which is what makes a column of money and a column of millimetres line up.
Space Mono 400 has exactly one role, and Pass 1 had to take it back to that role. It sets electrochemical figures only — 4,860.0 mA, 638,604 A·h, −800 mV, 2,500 A·h/kg, the potential scale — plus the one line the concept pins in mono, the tracked OF ALUMINIUM, OVER FIFTEEN YEARS beneath the display mass. Money is not an electrochemical figure, so money is never mono.
Scale: 17 px body (16 on phones), 15 px controls and ledger, 13 px annotations, 11 px drawing labels, and a display ramp of clamp(2rem, 4.2vw, 2.75rem) for the h1 against clamp(3.25rem, 15vw, 8.5rem) for the mass. Every clamp() and calc() on the page was checked for whitespace around its + and - operators: CSS parses 2rem+1vw as a single invalid token, the declaration is dropped in silence, and the size falls back to something that still looks deliberate. Nothing in a state assert can see it.
The signature: the Column
One SVG section through the water column, laid out in real CSS pixels rather than a fixed viewBox, so an 11 px annotation is 11 px at 375 and at 1200 instead of shrinking to five. The layout function measures the container, allocates a left gutter for the depth axis and the rotated zone annotations, a column for the section, and a strip for the potential scale, then computes the scene height from the measured badge height rather than a fixed aspect ratio.
Two view-fit frames, and a reason for each
The vertical frame is 0–8 m for the above-water, immersed-to-6 m and buried zones, and 0–18 m for the deep-diving zone. The two are visibly different rather than silently rescaled: the axis relabels (1 m steps against 3 m steps), the tide planes compress toward the top, and at 18 m the mean-sea-level mark is suppressed because it would collide with high water. Levels are assumed at HAT +1.0 and MSL +0.6 on Fremantle chart datum, and the page says they are assumptions.
The 1:10 detail inset is what makes the small state honest
A 300 mm zinc anode is 1.7 % of the 18 m frame and 3.8 % of the 8 m one. Drawn true to scale it is a mark, not a block — which is the truth, and which is why the section carries a detail panel drawing one anode at ten times the section’s scale, with its alloy, capacity, unit mass, real block dimensions and steel core. The enlargement factor is computed at draw time against the available panel width; where a viewport cannot hold ×10 the panel prints the factor it actually achieved, so the notation never lies. At every tested width (375 / 1000 / 1200) it holds ×10.
The anodes waste, and you can see what is gone
Each drawn anode is two shapes: a dashed teal envelope at its as-installed size, which never moves, and the solid remaining metal inside it. Over the entrance the solid shrinks along a smoothstep curve to the end-of-life profile — 15 % of the original section, because the utilisation factor is 0.85 — and comes to rest there. The gap between the dashes and the metal is the consumed anode. Under prefers-reduced-motion the scene renders that settled frame immediately: a static end state, never a blank one.
The wastage runs as a staggered wave down the structure (about 60 ms per anode inside a 2.2 s entrance, 18 ms inside a 480 ms redraw), driven from the animation loop itself. The whole drawing is assembled synchronously before the loop starts — an SVG scene assembled after the loop begins can receive no paint invalidation in headless Chrome, which is a defect only pixels find.
The potential scale draws the argument against magnesium
Beside the column runs a half-cell potential axis from −500 to −1,600 mV, carrying the −800 mV protection criterion as a heavy magenta rule, a tick at free-corroding steel, a hatched over-protection band below −1,100 mV, and a marker at the selected alloy’s open-circuit potential. Choose magenta’s worst case — magnesium in an estuarine berth — and the marker lands at −1,500 mV, deep inside the over-protection band, captioned past the band. That is the whole reason the seawater chip disables magnesium, drawn rather than asserted. Hovering or keyboarding onto an alloy chip ghosts that alloy’s open circuit onto the scale without changing state — you can compare zinc against aluminium before you commit to either.
In the buried state the scale re-references itself: AS 2832.1 states the same potential against a copper / copper-sulfate cell, so the axis relabels to mV vs Cu/CuSO₄, every marker shifts 50 mV, and the criterion line moves to −850 mV. Same steel, different reference electrode.
What is true to scale, and what is not
The section is true to scale vertically — zones, tide planes, the immersed dimension, and the anode blocks in both of their dimensions, all measured off the frame’s metres-per-pixel. Horizontal extent is a drawn representation, because the wetted area is a control spanning 20–600 m² and no honest plan geometry follows from a single square-metre figure. The page states that under the drawing rather than letting the reader assume otherwise.
The model
Everything is integer by construction. Current is held in tenths of a milliamp per square metre, charge in whole amp-hours, money in whole dollars; the price function asserts Number.isInteger on every field it returns and throws if anything is fractional. An independent oracle enumerated the full control grid — 21,600 cells, 6,930 of them priced, 5,400 refusals — and found 0 non-integer cells.
i_tenths = density_mA_per_m2 × coating_pct / 10 (tenths of mA/m²)
I_tenths = area_m2 × i_tenths (tenths of mA)
charge_Ah = ceil(I_tenths × life_years × 876 / 1000) (8,760 h a year)
mass_kg = ceil(charge_Ah × 100 / (capacity × 85)) (utilisation 0.85)
count = ceil(mass_kg / unit_kg)
subtotal = zone mobilisation + $2,400 design + $1,850 survey
+ count × (alloy supply + zone installation)
total = max(subtotal, $6,800 minimum)
| Scenario (full control vector) | Current | Charge | Mass | Anodes | Billed |
|---|---|---|---|---|---|
| Rest — piles · 180 m² · seawater · aged 30 % · 15 y · aluminium · to 6 m | 4,860.0 mA | 638,604 A·h | 301 kg | 26 | $21,500 |
| Same, but a new coating to AS/NZS 2312 (5 %) | 810.0 mA | 106,434 A·h | 51 kg | 5 | $10,475 |
| Cheapest reachable — 20 m² · seawater · aged · 5 y · aluminium · above water | 540.0 mA | 23,652 A·h | 12 kg | 1 | $6,800 |
| Bare steel — 180 m² · seawater · bare · 25 y · zinc · to 6 m | 16,200.0 mA | 3,547,800 A·h | 5,352 kg | 536 | $267,810 |
| … the same structure, newly coated | 810.0 mA | 177,390 A·h | 268 kg | 27 | $20,945 |
| Dearest reachable — wall · 600 m² · seawater · bare · 25 y · zinc · 6–18 m | 54,000.0 mA | 11,826,000 A·h | 17,838 kg | 1,784 | $1,194,210 |
The cheapest reachable output is $6,800, which is exactly the services grid’s from $6,800 floor — the estimator and the rate card cannot disagree. The job minimum binds in 191 of the 6,930 priced cells and every line sits inside it; nothing is ever added on top.
The coat-it-first note is the commercial argument
Above 2,000 kg the page stops selling anodes and tells the client to spend the money on paint instead. It fires in 1,208 priced cells. At 180 m² of bare steel over twenty-five years on zinc, that is 5,352 kg and 536 anodes for $267,810 against 268 kg and 27 anodes for $20,945 if the structure is coated to AS/NZS 2312 first — a twenty-fold difference in metal and a thirteen-fold difference in price, and we do not do coatings.
The refusal
Fresh water sits around 8,000 Ω·cm. Aluminium passivates in it; zinc has not the driving voltage to push useful current through that resistance. So the fresh-water chip prices nothing at all: every alloy and every zone disables, the badge replaces the total with “galvanic anodes won’t protect this — you want impressed current, and that’s a different design”, and the harness asserts the absence of any dollar figure on every computed surface — badge, ledger, total, display moment, hero figure and the plain-text mirror. 5,400 of the grid’s 21,600 cells are that state.
Anode block geometry, derived not invented
| Alloy | Capacity | Block | Density | Derived mass | Nominal |
|---|---|---|---|---|---|
| Al–Zn–In | 2,500 A·h/kg | 500 × 100 × 90 mm | 2,700 kg/m³ | 12.15 kg | 12 kg |
| Zinc, ASTM B418 II | 780 A·h/kg | 300 × 75 × 62 mm | 7,140 kg/m³ | 9.96 kg | 10 kg |
| Magnesium | 1,230 A·h/kg | 600 × 100 × 86 mm | 1,740 kg/m³ | 8.98 kg | 9 kg |
The forced chip, and the chain that unwinds it
The alloy is capped by two independent controls — the environment (electrochemistry) and the design life (magnesium’s own self-corrosion) — so it needs a restore memory and a pinned partial-unwind behaviour. The force order is aluminium, then zinc, then magnesium. The memory is cleared by any explicit pick made while the chip set is free, and survives until the remembered alloy becomes valid again. Driven end to end in every pass:
| # | Action | Alloy | Memory | Why |
|---|---|---|---|---|
| 1 | Estuarine, 10 y, user picks magnesium | Mg | — | Free choice clears the memory |
| 2 | → open seawater | Al forced | Mg | Magnesium over-protects in seawater |
| 3 | → 20 years | Al held | Mg | Magnesium now invalid on both counts |
| 4 | → buried in soil | Zn forced | Mg | Partial unwind: soil allows Mg again, but 20 y does not — and aluminium passivates in soil |
| 5 | → 10 years | Mg restored | cleared | The remembered alloy is valid again |
| 6 | → fresh water | all disabled | — | Refusal — no galvanic design exists |
| 7 | → estuarine | Mg kept | — | Still valid, so nothing moves |
The installation zone carries the same machinery in miniature: a buried environment forces the buried zone and disables the three wet ones, the wet environments disable the buried zone, and the remembered wet zone comes back when you return to water. Every disabled chip carries its reason on the page in the trade’s own words — “aluminium passivates in soil. Zinc or magnesium.”
Where our oracle disagreed with the brief
Every figure in the specification was re-derived here in an independently written oracle — 78 assertions over the same 21,600-cell grid — rather than trusted because it was written down. It reproduced the cell counts (21,600 / 6,930 priced / 5,400 refusals / 191 minimum-binding / 1,208 note-firing / 0 non-integer), every worked figure, and every measured contrast ratio exactly. Six things did not match, and in each case the page ships the reading that reproduces the pinned endpoints, with the disagreement written down here instead of quietly resolved.
- The smallest subtotal is $5,975, not $6,015. The brief names 20 m² · seawater · aged · 5 y · aluminium · above water and calls its $6,015 subtotal the smallest on the grid. That cell’s arithmetic is correct and it ships unchanged as the worked example. But a sweep of all 6,930 priced cells finds a cheaper one: 20 m² · seawater · new coating · 5 y · zinc · above water needs 6 kg of zinc, so one 10 kg anode, and subtotals $5,975. Both sit under the $6,800 job minimum, so the pinned endpoint — cheapest billed output equals the services-grid floor — is unaffected. This is the classic shape: a “smallest X” read off a hand-picked cell rather than produced by a sweep over the axes the claim quantifies over.
- The detail inset’s notation. The brief pins a “1:10 detail inset”. Drawn at ten times the section’s scale, the drafting notation for that is an enlargement (10:1), not a reduction (1:10). The panel ships as DETAIL A · ×10 OF SECTION SCALE, which is unambiguous, and the factor is computed at draw time so a viewport that cannot hold ×10 prints the factor it actually achieved.
- The buried state needs a second half-cell. The pinned criterion clause — protection criterion −800 mV vs Ag/AgCl per AS 2832.3 — ships verbatim in every priced state, as pinned. But a buried design is governed by AS 2832.1, which states the same potential against a copper / copper-sulfate cell and therefore reads −850 mV. Shipping a seawater reference electrode on a buried job is exactly the error the tradesperson reading this page would catch, so the buried state adds a second line saying so, and the potential scale re-references with it.
- The buried zone’s frame is unpinned. The brief pins the 0–8 m frame to “the above-water and to-6 m zones” and 0–18 m to the deep zone, and never names a frame for the buried zone. It takes the 0–8 m frame, drawn as a battered trench in native soil rather than a water column.
- “27 mA/m²” against “one decimal of a milliamp”. Display rounding is pinned as one decimal, but the pinned ≤640 px badge short form reads 180 m² · 27 mA/m² · 15 y. Both ship: total current always carries its decimal (4,860.0 mA, as the worked figures pin it) while the per-square-metre applied density strips a trailing .0. Enumerated over the whole grid, the applied density takes nine values and 4.5 mA/m² is the only fractional one, so the rule is exact rather than convenient.
- The job-minimum note had no pinned string. Every other note in the brief is pinned as a template; the minimum’s was not. It ships as “job minimum $6,800 applies — every line above sits inside it, nothing is added”, with the subtotal printed beside it, and lives on the ledger and the a11y mirror only (no badge form).
One further reading, stated rather than corrected: the brief calls the signature a section drawn “to true scale”. It is true to scale vertically, on the axis that carries the argument. See What is true to scale above.
The three passes
Pass 1 — Craft
- Space Mono was doing eight jobs. Eyebrows, ledger amounts, the hero price, stepper readouts, service prices, map labels and every drawing annotation were mono. The brief pins it to electrochemical figures only. Everything else moved to Public Sans with tabular figures; the hero total and the installed total moved to Fraunces. The page immediately read like a report instead of a terminal.
- A specificity bug swallowed the hero price.
.hero-pull p(0,1,1) beat.hero-total(0,1,0), so the headline figure rendered at 17 px instead of 42. Scoped to.hero-pull .hero-total. - An ordering bug left the header CTA on at 375.
.btn{display:inline-flex}is declared after themax-width:520pxmedia query, so the same-specificity.mast-cta{display:none}lost on source order and the button wrapped to two lines in the masthead. Re-scoped toheader.site .mast-cta; the 375 masthead is now wordmark plus phone, checked by comparing the wordmark’s right edge against the call link’s left edge. - The signature missed the thumbnail. At 1200 the scene started at y = 858, so neither the price badge nor any visible text node carrying the rest total reached the 750 px fold. The section head moved into the right-hand grid column, the hero was compacted, and a live total was added to the hero card. The scene now starts at 469 and the badge’s box ends at 552, with the first row of anodes reaching the fold.
- Scene composition. Zone labels collided with the pile group — moved into the left gutter as rotated drafting annotations, shown only where the band is tall enough to hold them. The deck beam was drawn above the frame datum and collided with the badge — moved to 0–0.5 m below deck level, where a deck actually is. The potential scale’s inline descriptions overflowed the SVG at both 375 and 1200 — removed, and replaced with a wrapped legend line under the column.
- The buried state was one flat wash. The backfill rectangle spanned the whole column, so native soil never appeared. Replaced with a battered trench, and the −800 mV axis tick was suppressed where it collided with the −850 mV criterion label.
- Contrast measured, not assumed. 39 pairs computed from the shipped hexes; every figure matched the brief exactly, including all six forbidden-ground failures.
Pass 2 — Depth
- The as-installed envelope. An anode wasted to 15 % of its section is a 1.5 px sliver at 375 — honest and nearly invisible. Each anode now draws a dashed teal outline at its installed size that never moves, with the remaining metal solid inside it. The consumed anode became a visible quantity instead of an absence.
- A staggered wave, not a uniform fade. The wastage runs anode by anode down the structure on a smoothstep curve, ~60 ms apart on the cold-load entrance and ~18 ms apart on a redraw.
- The micro-interaction. Hovering — or keyboarding onto — an alloy chip ghosts that alloy’s open-circuit potential onto the half-cell scale without touching state, so zinc and aluminium can be compared before either is chosen. Driven in the harness: the ghost appears, disappears on leave, and the state probe is unchanged.
- The second read. Magnesium’s marker lands at −1,500 mV, inside the hatched over-protection band, captioned past the band. Nothing announces it; it is simply there when a visitor picks the estuarine chip and then wonders why seawater will not let them.
- Bare steel corrodes on the drawing. Choosing the bare-or-heavily-corroded coating paints a corrosion band on the steel through the tidal zone — the one place the corrosion token is ever used, and the zone where a real pile actually goes.
Pass 3 — Hardening
- A resize must never re-enter the entrance. Taking a clipped screenshot changes device metrics and fires the resize handler; an entrance gated on anything but a cold-load flag would photograph an empty scene. The entrance runs on a
firstDrawflag with a settle-timer backstop, resize redraws instantly at the settled profile, and the harness assertsfirstDraw === false,wasteFraction === 1and an unchanged total across a viewport change. - The dock breakpoint was measuring the wrong thing. The badge docked below the artwork on scene width, so at a 1000 px viewport — where the two-column grid makes the scene 569 px — it docked when the wave rule says it should sit on the scene. Now judged on viewport width: docked at ≤640, on-scene above, checked at 641 / 760 / 900 / 1000 / 1100 with the badge never wider than the column.
- Rectangle-intersection, not a formula. The badge’s box is measured against every drawn anode envelope and every steel rectangle at 375, 1000 and 1200, and at DPR 2 — zero intersections. The scene’s sky band height is a function of the badge’s measured height, so the clearance is structural rather than tuned.
- A number-only pass over the prose. Every figure in body copy was re-derived from the shipped model. The FAQ’s coating comparison (51 kg against 301 kg on 180 m² over fifteen years) is the model’s own output. The trust strip said “14 years” against a 2011 founding — corrected to fifteen. The three anode block sizes were derived from real alloy densities and land within 0.15 kg of their nominal masses.
- Removed one ornament, and it was a dishonest one. The service-area map carried a scale bar reading “10 km”. Measured against its own pin geometry the bar was out by roughly 14 % north–south and Perth sat about twice its real distance from Fremantle. A schematic service-area map cannot honestly carry a scale bar, so the bar is gone, the map is relabelled SCHEMATIC — NOT TO SCALE, and the geography was tightened anyway.
- Form validation proved, not read. Chrome compiles
patternattributes as v-flag regexes, which reject literal specials older flavours accepted — a dead pattern validates nothing while looking perfectly fine. Each pattern is driven throughcheckValiditywith a deliberately invalid value and then a valid one. Empty submit keeps the confirmation panel hidden and raises real validation signals; a filled submit clicksbutton[type=submit]specifically and shows the panel. - Reduced motion, keyboard, rapid fire. Reduced motion renders the settled end-of-life frame immediately, never a blank. Every chip is reachable and operable by keyboard with a visible focus ring. A rapid-fire drive fires twelve control clicks in one evaluate with no settle between — every handler bumps the animation token before the state swap, so no in-flight loop can close over a stale scene.
The harness ends at 210 assertions, 0 failures, with zero console errors and zero failed requests on both pages.
Local SEO we’d implement for the real business
This demonstration ships no business-shaped structured data — the live JSON-LD is WebPage, CreativeWork, WebSite and a BreadcrumbList, because marking a fictional contractor up as a real one would pollute a real index. For an actual client we would ship the block below, with the reviews wired to whatever they already collect.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ProfessionalService",
"@id": "https://halfcellcp.com.au/#organisation",
"name": "Halfcell Cathodic Protection",
"description": "Galvanic anode design to AS 2832.3, supply, dive installation and
half-cell potential surveys for marine and buried steel.",
"url": "https://halfcellcp.com.au/",
"telephone": "+61 8 9XXX XXXX",
"email": "office@halfcellcp.com.au",
"priceRange": "$$$",
"image": "https://halfcellcp.com.au/img/anode-install.jpg",
"logo": "https://halfcellcp.com.au/img/logo.png",
"address": {
"@type": "PostalAddress",
"streetAddress": "Unit 4, 12 Quill Way",
"addressLocality": "Henderson",
"addressRegion": "WA",
"postalCode": "6166",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -32.1614, "longitude": 115.7712 },
"areaServed": [
{ "@type": "City", "name": "Fremantle" },
{ "@type": "City", "name": "Henderson" },
{ "@type": "City", "name": "Kwinana" },
{ "@type": "City", "name": "Rockingham" }
],
"openingHoursSpecification": [{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "06:30", "closes": "17:00"
}],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Cathodic protection services",
"itemListElement": [
{ "@type": "Offer",
"itemOffered": { "@type": "Service", "name": "Cathodic protection design to AS 2832.3" },
"priceSpecification": { "@type": "PriceSpecification",
"price": "2400", "priceCurrency": "AUD" } },
{ "@type": "Offer",
"itemOffered": { "@type": "Service", "name": "Baseline potential survey, Ag/AgCl half-cell" },
"priceSpecification": { "@type": "PriceSpecification",
"price": "1850", "priceCurrency": "AUD" } }
]
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9", "reviewCount": "38"
},
"review": [{
"@type": "Review",
"author": { "@type": "Person", "name": "A real, named client" },
"reviewRating": { "@type": "Rating", "ratingValue": "5", "bestRating": "5" },
"reviewBody": "Surveyed before quoting and only re-anoded the nine piles that needed it."
}]
}
</script>
Alongside it: a verified Google Business Profile with the Henderson yard as the primary location and Cockburn Sound as the service area, FAQPage markup on the six questions already written here, and one page per structure type (jetty piles, sheet-pile walls, buried pipelines) because those are the queries, not “cathodic protection Perth”.
What would change for the real client
- Their photographs. Every visual here is procedural — that is the collection’s constraint, not a recommendation. A real Halfcell would want dive footage and before/after anode shots, and the section drawing would stay, because no photograph explains a current-density calculation.
- Their anode schedule. The alloy table is hard-coded. A real build reads capacities, unit masses and supply prices from the supplier’s catalogue so a price rise is a data change, not a deploy.
- Their job system. The enquiry would post to simPRO or AroFlo — both are common in WA commercial marine and industrial contracting — creating a lead with the on-page design attached as the first note, so the estimator opens the job already knowing the wetted area, the coating condition and the design life the client chose.
- Their survey data. Potential surveys come back as spreadsheets of chainage, depth and millivolts. A client portal plotting those against the −800 mV criterion — the same scale drawn on this page — is the natural second phase, and it is what turns a one-off design fee into a survey retainer.
- Their reviews. Pulled live from the Google Business Profile and marked up as real structured data, replacing the demonstration copy here.
- Their compliance pack. Dive-team qualifications, SWMS and insurance certificates behind a single “send me your paperwork” button, because that request arrives on every commercial job and answering it manually costs an hour each time.