Faraday & Vane The site Index

How it was made · Site 406 · Generative Assets

Faraday & Vane — a sphere you can’t fit in the picture

Faraday & Vane is a fictional Welshpool lightning-protection contractor built for the facility manager whose insurer has just asked whether the building has a system. The page has one job: turn “do I need this and what does it cost” into a booked site risk assessment, with the terminal count, the down-conductor count and the price already drawn on the screen — including the answer not from a web page.


The signature: the rolling sphere

AS 1768 sizes a lightning protection system with the rolling-sphere method. You roll a sphere of a radius set by the protection level over the structure; wherever it touches, a strike can reach. Air terminals hold the sphere off the roof, and the only real question is how far apart they can stand before it sags between them and touches anyway.

Two tips of height h spaced d apart, a sphere of radius R resting on both:

sag  s     = R − √(R² − (d/2)²)
protected  while s ≤ h
so d_max   = 2·√(2Rh − h²)

That is the whole geometric argument of the site, and the drawing is a true-scale elevation of it: at Level III the sphere is 45 m of radius against a 40 m roof, so it is 2.25× the length of the building it is protecting. You cannot fit it in the frame, and the page does not pretend otherwise — the arc is cut by the top edge and sweeps the full width. That is the honest picture and it is the thing a visitor describes to someone else.

…and the grid pitch is not d_max

This is the correction that drove a change to the spec, and it is the page’s second read. d_max is the section condition. It answers one question: how far apart can two terminals stand in a line before the sphere sagging between them touches the roof. The sphere sags at the midpoint of that line, where its horizontal reach from either tip is d ÷ 2.

A roof is not a line. On a square grid the sphere comes to rest on four tips and sags deepest at the centre of the square, and the reach from a tip to that centre is the half-diagonal, p·√2 ÷ 2 — larger than p ÷ 2 by exactly √2. So the grid condition is tighter than the section condition by exactly √2, and the greatest legal pitch is:

p_max      = d_max ÷ √2
held as    p_max = isqrt(⌊d_max² ÷ 2⌋)     (millimetres, no float)

Spacing a grid at d_max leaves the middle of every square unprotected. The first draft of this site’s brief did exactly that, the model was rebuilt on p_max, and the two figures are now both drawn rather than one of them being buried: Detail A ghosts them side by side at true horizontal scale — the run, then p max, then d max, with the √2 braced between the last two — and the roof plan tints one square and picks out its diagonal, because the diagonal is the direction that actually has to fit inside d_max. The diagonal is exactly the sort of thing a customer cannot check, which is what this drawing is for.

Measured over the 2,880 (length × width × level × tip × height) vectors the terminal grid is defined on, the correction moved 2,696 of them. The worst price move is +39.3 % — an 80 × 40 m roof 4 m high at Level III on a 500 mm tip, $41,734 → $58,134. The worst count move is larger: +125 %, a 20 × 20 m roof at Level III on a 1,500 mm tip, where 2 × 2 terminals becomes 3 × 3. The most-terminals extreme over the whole grid went from 66 to 112, and the fewest from 4 to 6.

It moved no pinned endpoint: the rest vector still draws 12 terminals for $20,214, the cheapest cell is still $7,022 clamped to the $7,500 grid floor, and the metal-deck shed is still $14,294. It did flip the dearest cell, which is the part worth reading twice. At 80 × 40 × 30 m under Level I with a comms room, a terminal system is now $117,190 against $104,630 for the same building meshed — the two had been the other way around. The tighter the sphere, the tighter the grid and the more finials you buy, so at some size a mesh simply wins. The page now says so on the ledger whenever it is true, with the other system’s figure printed beside it.

Integer millimetres, never a float

Every length is held in millimetres and the square root is an integer square root (Newton, floored to the whole millimetre). Math.sqrt would put 18865.999999… into a displayed dimension on some cells; the integer root cannot. Money is held in whole dollars by construction — every rate in the model is a whole dollar — and the price function asserts Number.isInteger before it returns. The independent oracle enumerated all 23,040 priced cells and found 0 non-integer fields.

The table, as shipped

Reproduced independently in oracle-lightningprotection.mjs and asserted row by row against the running page. Each cell carries both figures: the section d_max first, then the grid pitch p_max after the arrow — the second is always the first divided by √2 and floored to the millimetre. A starred cell is one where d_max comes out tighter than the standard’s own mesh size for that level, which is what forces the design onto a mesh. Note that the force tests d_max, not the pitch: it is a question about the section, and changing it to test the pitch would have moved the two forcing pairs, which the brief pins.

Greatest legal air-terminal spacing in the section, and the square-grid pitch that follows from it, in millimetres, by protection level and terminal height
Protection levelSphere RMesh500 mm tip
d_max → p_max
1,000 mm1,500 mm
I — hospital, essential service20 m5 m8,888 → 6,28412,488 → 8,83015,198 → 10,746
II — school, public assembly30 m10 m10,908 → 7,71315,362 → 10,86218,734 → 13,246
III — commercial and industrial45 m15 m13,378 * → 9,45918,866 → 13,34023,042 → 16,293
IV — shed, low consequence60 m20 m15,458 * → 10,93021,816 → 15,42626,664 → 18,854

The force therefore fires on exactly two (level, tip) pairs — III/500 and IV/500 — across 960 cells each. On a concrete slab the resolution is a mesh. On a membrane, which cannot carry a mesh, the same constraint re-evaluates onto the terminal height and pushes the tips up to 1,000 mm instead. That is the partial unwind, and the page walks all six steps of it.

How the sphere rolls

It pivots. Resting on tips (k, k+1) the centre sits at angle −α from vertical over tip k+1; resting on (k+1, k+2) it sits at , where sin α = (d/2) ÷ R. Interpolating that one angle is rolling — there is no separate translation, and the contact geometry is correct at every instant. The faint dashed scallops left on the sheet are the locus the centre travels: that is the second read, and it is the drawing explaining its own motion.

The lowest point of the circle is always (cx, cy + R), so the callout ring tracks the true deepest penetration at every frame without a special case. Where there are no terminals — a mesh, or a metal deck that is its own air termination — the sphere sits tangent to the roof and the contact is marked in coral. That is not a failure state: on a 0.5 mm steel deck it is the design.


Palette

Argued from what is actually on the roof: 28 mm² bare copper tape, galvanised steel deck, and a storm. This is a dark site because the subject is a sky. Every ratio below was measured from the shipped tokens with WCAG arithmetic (contrast-lightningprotection.mjs, 45 pairs, 0 failures), not estimated.

#0F1419storm groundBlue-shifted, not neutral black — a Perth storm front is cold, and a neutral black would have landed the page on the “near-black plus one acid accent” default.
#18202Acard / sky liftThe same ground one step up. Cards and the upper sky share it, so the drawing and the chrome are the same material.
#E9EEF3light inkBody text and every word on every drawing. 15.86:1 on the ground, 8.04:1 on the roof deck — the worst ground it can land on. Forbidden grounds: none.
#A8B6C2muted inkEyebrows, captions and ledger labels only: 8.93:1 page, 7.93:1 card. It clears every scene fill numerically and is still kept off the artwork by decision — the drawing gets exactly one text colour so nothing on it reads as secondary.
#D08A52copperBare copper tape. Lines and marks: the conductor, the down conductors, the terminal shafts, the dimensions. 6.56:1 on the sky, 3.33:1 on the roof deck. As a fill it carries #0F1419 labels at 6.56:1 (hover #E5A470, 8.71:1).
#8FC0E0sphereThe sphere, its centre, its radius and the locus scallops. 9.51:1 on the sky, 4.82:1 on the roof deck. Forbidden ground: the card hairline — it is a scene token and never draws chrome.
#F0806Frefusal coralTwo jobs only: the point where the sphere reaches the structure, and the hazardous-area refusal. 7.07:1 on the sky, 4.65:1 on the building fill. Forbidden on the roof deck (3.59:1) and the earth (5.71:1 but reserved) — it marks sky-side geometry, never the deck itself.
#37485Aroof deckGalvanised sheet. The tightest ground on the page: the light ink still clears it at 8.04:1, which is why every label on the drawing is the light ink.

Three argued mid-tones — copper, cold sphere blue, refusal coral — keep the site off the “near-black plus a single acid accent” default; none of them is acid, and the black is blue-shifted rather than neutral. There is no serif anywhere and no column rules: the structure is the roof line and its dimensions.

Type

Archivo at width 125 for display — a wide industrial grotesque with enough width to carry a roof. IBM Plex Sans as the workhorse and IBM Plex Mono for every dimension, count and radius, because a drawing’s figures are monospaced or they are not a drawing. Body 17px on mobile, 18px above 900px.

The typographic bravery is the radius, set once and set large: the sphere’s radius lives in the drawing’s title block at up to 3.2rem of expanded 700, with the unit at 27 % of that size lifted to the cap height. It is a live figure — change the protection level and it changes.


The three passes

Each pass drove the form empty and filled, exercised every chip and stepper, walked the full force and partial-unwind chain step by step, drove the refusal, ran a rapid-fire burst with no settle between clicks, and read native-resolution screenshots at 375, 1000 and 1200.

Pass 1 — Craft

  • The badge covered the sphere. The badge started as an overlay pinned to the top-left of the drawing with the scene’s height computed from its measured height. It looked clean at rest and it was wrong: the arc sweeps the whole upper frame as the sphere rolls, and on an 80 × 40 m roof at Level I the circle’s top-left ran straight under the panel. There is no on-scene anchor that stays off the subject. It became a drawing title block docked directly beneath the elevation at every width — inside the signature container, never over the drawing — which is also where a title block belongs on a real sheet. The binding check is now a rectangle-intersection assert at 375 and 1200, not a clearance formula.
  • The signature sat 1,025 px down the page. The hero was a full-width copy band with the estimator below it, so the drawing missed the 750 px thumbnail line entirely. The scene moved into the hero as its second column and the controls and ledger moved below; the drawing now starts at about 120 px and the price prints in both the hero column and the title block.
  • The masthead collided at 375 and the probe said it didn’t. The wordmark’s sub-line is white-space:nowrap, so it overflowed its own flex box and ran under the call button while an element-rect comparison stayed green. The sub-line now drops “· Welshpool” below 430 px, and the harness measures the rendered text with a Range rather than the element box.
  • At 375 the trust signals were pushed under the fold by a seven-line lede and the sticky bar. The lede lost a sentence, the trust strip moved above the price figure, and the fold is now measured to the top of the sticky bar rather than to the viewport edge.
  • The sag callout’s leader ran straight through the roof line and the terminals. It became an elbow leader out of the ring and up into clear sky.
  • Detail A printed its sag label inside the lens between the chord and the arc, where it collided with the right-hand tip. It moved above the chord, where the arc never reaches.
  • The hazardous-area classified-zone box ran off the right edge of the frame; the tanks are now laid out into the measured room between the building and the frame edge.

Pass 2 — Depth

  • The radius, drawn. A dashed line from the sphere’s centre to its contact point, labelled with the live radius. It fills the empty interior of the arc and it explains the geometry without a sentence.
  • The centre locus. The dashed scallops above the terminals are the path the sphere’s centre travels as it rolls — an arc of radius R about each tip in turn. It is the second-read detail: on a first visit it reads as a construction line, on a second it is the motion itself, drawn.
  • Detail A for a mesh or a metal deck was a near-flat arc over an empty panel. It now draws a real roof section — the slab with its mesh at the level’s own centres, or the sheet with its ribs — and the sphere at a radius that actually reads as curved.
  • The √2 got drawn, and it got no panel of its own. The obvious move was a third panel explaining the pitch. The existing pair already had the right shape for it: Detail A is a section, so it took the two ghosted limits — p max and d max at true horizontal scale, with the ratio braced between them — and the roof plan is a plan, so it took the tinted square and its diagonal. One idea, one drawing each, nothing added to the layout. The three figures then repeat in the title block, the panel notes and the plain-text mirror, which is where a reader who wants the numbers rather than the picture will look.
  • Both panel titles became live: the grid / the mesh / the sheet / withheld, and the sag / the contact / withheld. A panel headed “the sag” over a drawing with no terminals was arguing with itself.
  • The hero’s caption is now derived from the running model rather than describing the rest state forever — change the roof to steel deck and it says “steel-decked… no finials at all”.
  • The terminal rate labels come off the chips entirely while the refusal stands. The page prices nothing at all in that state, not even a catalogue rate.

Pass 3 — Hardening

  • Entrance choreography runs on a cold-load flag with a 1.6 s settle-timer backstop and is driven from the animation loop, never from post-hoc DOM insertion. A resize never re-enters it — taking a clipped screenshot changes device metrics and fires the resize handler, which is how a previous wave photographed an empty scene while every assert stayed green.
  • The roll clock is wall clock, not a per-frame accumulator. It used to be tAcc += min(max(now − last, 0)/1000, 0.05) — clamped at zero because a first vsync timestamp can precede the performance.now() that scheduled the loop, and capped so a backgrounded tab did not jump. But a capped accumulator only advances when a frame is served, and a headless renderer taking a thumbnail services rAF on demand: at 60 sparse frames it is barely three seconds into a seven-second capture, so the sphere sits near its start position while every state assert stays green. It is now tAcc = (now − origin − hidden)/1000, and only document.hidden pauses it — a thin frame budget never does. Driven under 20× CPU throttling the page served 61 frames in seven seconds and the sphere finished at cx 380.6 against 382.9 on an unthrottled run of 1,842 frames. The old code could not have got past 61 × 0.05 = 3.05 s.
  • Every SVG state change goes through setAttribute. SVG elements have no hidden IDL property, so el.hidden = true lands as an expando and the state stays right while the pixels stay wrong.
  • Form patterns were proved by driving checkValidity on a deliberately invalid value, not by reading the attribute. Chrome compiles pattern as a v-flag regex, which rejects unescaped literals that older flavours accepted — a dead pattern looks identical to a working one.
  • The rest state comes to rest visible: after driving the controls and waiting with nothing poking the page, the scene root is asserted fully opaque. The sphere’s own opacity breathes but never drops below 0.6, so the signature is alive at any capture instant rather than phase-tuned to a settle time.
  • Removed (the Chanel rule): the big “45 m” that had been floated in the sky at the top-right of the drawing. It duplicated the title block, it collided with the arc once the sphere was allowed to fill the frame, and the drawing is better with one fewer thing in it.
  • 375: masthead measured as text, tap targets at 44 px and up, sticky bar owning both a tel: link and an in-page anchor that is asserted to actually reach the form, no horizontal overflow on either page, and the guide’s tables wrapped in a scrolling container with a deliberate minimum width.
  • Both pages were scanned for a word character followed by = and a typographic double quote before committing. Twenty-one of those shipped in a guide last wave and every assert passed while the styling silently vanished. Zero hits here.

Where our model disagreed with the brief

The model was reimplemented from scratch in a separate file rather than read out of the page, and it enumerated the whole 34,560-cell control grid: 23,040 priced, 11,520 hazardous-area refusals, the minimum charge binding in 14 cells, 960 forced-to-mesh and 960 forced-tip cells, 0 non-integer fields. Every pinned money figure reproduced exactly — the $20,214 rest total, the $14,294 metal deck, the $7,022 cheapest subtotal clamped to the $7,500 grid floor, the $117,190 dearest cell against $104,630 for the same building meshed, the 112-terminal maximum. Five prose claims did not. Four of them move no dollar and are shipped as the brief pins the model; the fifth moved the model itself, and is the reason this page was rebuilt.

  1. “The model floors down conductors at 2 and the enumerated minimum IS 2.” The floor of 2 is in the model and is shipped, but it never binds. The smallest perimeter on the grid is 2 × (20 + 10) = 60 m and the widest down-conductor spacing is Level IV’s 20 m, so the minimum reachable count is 3, and the floor does no work in any of the 23,040 priced cells. The conclusion the brief drew from it — that no “1 down conductor” singular is reachable — holds, by a wider margin than claimed.
  2. “The sphere is the subject and it is always larger than the roof.” It is not. Level I’s sphere is 40 m across and the length stepper reaches 80 m, so on 4 of the 24 (length, level) pairs — and 3,840 priced cells — the building sets the frame, worst at 80 m against Level I, where the roof is twice the sphere’s diameter. The pinned view-fit formula max(building length, 2R) is right and is what shipped; only the sentence beside it was wrong. The building-to-sphere ratio is never cheated, and at its worst (a 20 m roof at Level IV) the building really is 16.7 % of the sphere’s diameter.
  3. The drawn cap of 12 lives in the roof plan, and it has to cap columns as well as rows. The plan draws the whole nx × ny grid, whose enumerated maximum is 112. The first shipped cap drew every terminal across and as many rows back as fit under twelve — nx × min(ny, ⌊12 ÷ nx⌋) — which was safe only because the widest row was 11. The √2 pitch correction took the widest row to 14 (an 80 m roof at Level I on a 500 mm tip), and that formula quietly returns 14 there: it broke its own cap. The shipped version caps both axes, cols = min(nx, 12) then rows = min(ny, max(1, ⌊12 ÷ cols⌋)), which is enumerated at 12 or fewer everywhere and equal to the full count whenever the full count fits. The drawn count is a set of seven values {6, 7, 8, 9, 10, 11, 12}, so the cap note takes the drawn count and never the pinned literal “12”.
  4. So the elevation needs the cap too. A side elevation shows one row, and one row can now be 14 terminals — over the cap. It draws the first 12 at their true positions and ghosts the remainder in dashed light ink, which is the same device the plan already used for the rows it does not draw, and the sphere rolls only over the ones that are drawn. The published state carries terminalsInElevation and elevationGhosted so the harness can assert the picture rather than the intention.

And a fifth item, which is why this page changed. The brief’s first draft used the two-tip spacing d_max as the grid pitch on both axes. That is optimistic: a sphere resting on the four corners of a square dips deepest at the centre, where the reach is the half-diagonal, so the grid condition is tighter than the section condition by exactly √2 and a d_max grid leaves the middle of every square unprotected. This was first shipped as a stated caveat rather than a fix. That was the wrong call — a caveat is not a defence for a drawing that is wrong — and the brief was corrected to p_max = d_max ÷ √2 and this page rebuilt on it. The two figures are now both on the drawing, which is a better page than the one that hid the problem in a paragraph. The derivation is above.


Where the numbers come from

Price model
LineRateBasis
Design and AS 1768 risk assessment$1,850flat, every job
Air terminal installed$180 / $240 / $310by 500 / 1,000 / 1,500 mm
Roof conductor$38 / mperimeter plus the interior grid lines
Down conductor$46 / mbuilding height × the conductor count
Earth electrode and pit$520 eachone per down conductor
Testing and certificate$780flat, every job
Comms surge protection$3,200only where the contents call for it
Minimum charge$7,500a floor on the whole job — every line sits inside it

Down conductors are max(2, ⌈perimeter ÷ spacing⌉) where the spacing is the protection level’s own (10 / 10 / 15 / 20 m). That floor of 2 is dead code — the enumerated minimum over all 23,040 priced cells is 3, so the outer max never binds. It is shipped because the brief pins the formula, and it is written down here rather than quietly deleted. The cheapest cell the estimator can produce is $7,500, which is exactly the “from $7,500” floor on the services grid: the page cannot quote a number lower than the number it advertises.

The refusal is reachable and it costs the sale. Select fuel or LPG storage and every priced surface is replaced — badge, ledger, plan, detail, and the chips’ own rate labels. Protecting a hazardous area is a different design: bonding and separation distances, equipotential earthing, and an assessment of the classified zones before anything is fixed to a tank. 11,520 of the 34,560 cells in the grid are that answer.


Conversion decisions

  • The drawing is the argument, so it is in the hero. A facility manager who does not know what a lightning protection system is learns it in one picture: a sphere far bigger than the building, held off the roof by four small copper rods. The price is in the title block under the drawing and again in the hero column, so the 1200 × 750 preview carries both.
  • The refusal is a conversion feature. A page that stops rather than guess is the single most persuasive thing on it, and the same is true of the metal-deck note — telling a builder that his roof already is the air termination costs the finial line and wins the earthing package.
  • The estimator hands off to the form. “Send this to the estimator” pre-fills the roof select and writes the configured scenario into the message, so an enquiry arrives warm and the callback conversation starts from a drawing both parties have seen.
  • Form fields are the ones a lightning contractor actually needs to price a visit: name, phone, suburb, building type, roof, and what prompted it. Roof type carries a “not sure — come and look” option, because half the enquiries genuinely don’t know and forcing a guess loses them.
  • Click-to-call in the header at every width, plus a sticky bar below 640 px owning both a tel: link and an in-page anchor to the form. The copy is in the trade’s voice (“Ring the shed” would suit a wheatbelt operator; a Welshpool contractor gets “Call the shed” and “Get on the roof list”).
  • An honesty line travels with the layout. Wherever the computed layout appears, so does the line saying the sphere tells us where a strike can reach and the real answer is an on-site assessment. The words “certified”, “guaranteed” and “compliant” never describe a computed layout anywhere on the page, and the page never claims a system prevents a strike — the standard’s language is a preferred path to earth, and that is the language used.

Local SEO we’d implement for the real business

The live page emits only WebPage, WebSite and BreadcrumbList structured data, because Faraday & Vane does not exist and publishing business or review markup for a fictional trader would be dishonest markup in a real index. For a real client we would ship the following — an Electrician is the correct schema.org organization subtype for a licensed electrical contractor, and reviews would come from the client’s own verified feed, never written by us:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Electrician",
  "name": "Faraday & Vane Lightning Protection",
  "url": "https://faradayandvane.com.au/",
  "image": "https://faradayandvane.com.au/img/welshpool-yard.jpg",
  "telephone": "+61 8 XXXX XXXX",
  "priceRange": "$$",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Unit X, XX Example Road",
    "addressLocality": "Welshpool",
    "addressRegion": "WA",
    "postalCode": "6106",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": -32.01, "longitude": 115.95 },
  "areaServed": [
    { "@type": "City", "name": "Perth" },
    { "@type": "AdministrativeArea", "name": "Perth metropolitan area" }
  ],
  "openingHoursSpecification": [{
    "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
    "opens": "06:30", "closes": "16:00"
  }],
  "hasOfferCatalog": {
    "@type": "OfferCatalog",
    "name": "Lightning protection services",
    "itemListElement": [
      { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "LPS design and install to AS 1768" } },
      { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Annual test and certificate" } },
      { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Earth-resistance testing" } }
    ]
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.8", "reviewCount": "37"
  }
}
</script>

The aggregateRating block above is shown as a code sample only. It would be populated from the client’s verified review platform and would never be hand-written — that is the difference between structured data and decoration.


What would change for the real client

  • Their photographs. Every visual here is procedural — SVG, CSS gradients, no raster assets anywhere — which proves the layout carries without stock photography. A real Faraday & Vane would drop in roof shots, an EWP on a parapet, a pit lid open with a test set in it.
  • Their job and asset register. simPRO or AroFlo is the right integration here, and it matters more for this trade than most: a lightning protection system is an annually tested asset, so the recurring revenue is the test certificate, not the install. The enquiry form would create the lead, the site visit would create the asset, and the annual test would recur against it automatically with the certificate attached to the asset record.
  • Their real numbers. The rates here are plausible Perth figures chosen to make the model internally consistent; a real build starts from their actual price book, and the estimator’s cheapest output is checked against the advertised floor as a standing test.
  • The estimator becomes a lead-scoring tool. The configured vector is worth more than the enquiry: a Level I building with a comms room and 30 m of height is a different sales conversation from a 20 × 10 m shed, and the CRM should know which one arrived.
  • Their reviews feed. The three testimonials here are demo copy on a page declared fictional. A real site pulls Google reviews and marks them up properly.