Build guide · Site 247 · Industry Demos VII
How Crownwork Tree Care was made.
A fictional tree care operator for Kalamunda and the Perth foothills — pruning, removals and stump grinding for hills owners with big marris over the house. The page has one job: book a free tree assessment. Every visual is procedural — SVG, gradients and CSS only, no photography, no libraries.
Concept
Crownwork Tree Care ("crown work" is the trade's own word for pruning done properly) sells quiet competence at height — the opposite of chainsaw-cowboy letterbox flyers. The art direction is looking up through a marri canopy at 10am: dappled light, a climber's rope line just visible, and everything below it disciplined and phone-first. The audience is a hills owner who fears a tree, was told to "get it looked at" at inspection, or wants a stump gone — and who has learned to distrust prices scrawled on a card.
Palette
Argued from the canopy overhead, with the ink/line split applied: sap amber is a LINE/MARK token (cut markers, rope lines, the CTA fill) and never body text on the light ground.
Type
- Archivo (600–800) — display and headings. A sturdy grotesque set wide: signage on a truck door, not a boutique serif. The one moment of typographic bravery is the masthead's amber-underlined "on ropes, not luck".
- Mulish (400–700) — body and UI. Warm, legible at 16.5px, disappears behind the content.
- IBM Plex Mono (400–600) — heights, prices, suburbs, the estimate card. Everything measured or counted is set in mono, so the page's honesty reads typographically.
The Canopy Estimator — model & measured numbers
The signature element: size chips, job chips and an access toggle drive a procedural SVG eucalypt beside a house gable. The tree scales to the size chip against a metres rule; the job highlights on the tree itself — deadwood limbs mark in sap amber, a reduction line arcs across the crown, removal ghosts the tree to a stump, and stump grind zooms the base. The estimate card renders in mono, and "Use this in my enquiry" pre-fills the assessment form with the configured scenario.
Factor model, derived from the pinned anchors
Base rates are the spec's pinned services-grid floors (small tree, open yard). Size factors are crew-day maths: a medium tree is roughly an extra half-day share (×1.5), a large one an extra day plus rigging volume (×2.5). Tight or over-structure access adds rigging and lowering time: ×1.35 on climb jobs, ×1.25 on stump grinds (the narrow-access grinder fits a 900 mm gate but takes more passes). Outputs round to the nearest $10. Large removals are deliberately never auto-priced — the pinned anchor is "from $2,800, quoted on site", so the card says exactly that and explains why (climb plan, drop zone, sometimes traffic control).
| Job (base) | Small ×1.0 | Medium ×1.5 | Large ×2.5 |
|---|---|---|---|
| Deadwood & prune ($380) | $380 | $570 | $950 |
| Crown reduction ($780) | $780 | $1,170 | $1,950 |
| Full removal ($650) | $650 | $980 | from $2,800* |
| Stump grind ($280) | $280 | $420 | $700 |
Honest-numbers details: the scene caption states the drawn tree height measured from the geometry (22 px per metre against the rule: ≈15 m full-size, ≈9.5 m medium, ≈4.6 m small — each inside its chip's stated band). Real institutional numbers are quoted where they are genuinely correct advice — SES 132 500 for storm roof damage, Western Power 13 13 51 for vegetation within 3 m of their lines — while every number belonging to the fictional business uses the reserved (08) 9000 0247 pattern and placeholder registrations.
Techniques
- Procedural SVG scene — the eucalypt, gable, metres rule and stump are hand-placed paths. Layout positions live in SVG transform attributes; anything animated (tree scale, zoom, sway) animates via CSS/inline style on separate nested groups, so no stylesheet rule ever discards a presentation attribute.
- Tree scaling & stump zoom — the tree scales via style.transform on an attribute-free group with a fixed origin at the base. The stump zoom is normalised to the stump, not the tree: scale = 2.6 ÷ sizeFactor, so "the base, up close" reads identically at every tree size.
- Reduction line draw-in — stroke-dash with butt caps (no round-cap stray dot), drawn once when the scene first enters the viewport (IntersectionObserver), fully drawn from t=0 otherwise — so the 7-second thumbnail settle and the reduced-motion path always capture a drawn state.
- Hero canopy — one reusable gum-leaf path stamped 42 times via <use> in three greens, with dapple as radial gradients and the rope line in sap amber. Position on outer groups (attributes), sway on inner groups (CSS keyframes), killed under reduced motion.
- No libraries, no rasters — the whole page is HTML, CSS and ~220 lines of vanilla JS. State probe at window.__arborist.
Conversion decisions
- Phone-first: tel: link in the header at every width, and a sticky mobile bar where "Call now" is the filled action — a worried tree owner phones, they don't type. The form exists for the researcher and the after-hours browser.
- Estimator above services: the trade's biggest objection is price opacity. Showing honest maths before the services grid earns the scroll; the grid then confirms the same floors, so the page never argues with itself.
- Form after FAQ: council approval, insurance and "is my tree dangerous" are the real hesitations — answered before the ask. Fields are only what a scheduler needs (name, phone, suburb, job, notes); the estimator handoff pre-fills job and notes so the enquiry arrives warm.
- Assessment, not quote: the CTA verb is "free tree assessment" throughout — it's the trade's genuine entry product and a softer promise than "quote" for a fearful owner.
- Local confirmation: submit renders a designed confirmation naming the caller and suburb, states plainly that this is a demonstration and nothing was sent, and routes genuine emergencies to the phone and the SES. No fake network round-trip.
Local SEO we'd implement for the real business
This demonstration page ships only WebPage schema naming it a demonstration — fictional LocalBusiness or Review markup in a real index would be dishonest. For a real Crownwork, we'd ship:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Crownwork Tree Care",
"description": "Pruning, tree removals and stump grinding across
Kalamunda and the Perth foothills.",
"telephone": "+61-8-XXXX-XXXX",
"url": "https://crownworktreecare.com.au",
"address": {
"@type": "PostalAddress",
"addressLocality": "Kalamunda",
"addressRegion": "WA",
"postalCode": "6076",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -31.97, "longitude": 116.06 },
"areaServed": ["Kalamunda","Lesmurdie","Gooseberry Hill","Forrestfield",
"Maida Vale","Darlington","Mundaring","Roleystone"],
"openingHoursSpecification": [{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "07:00", "closes": "16:00"
}],
"review": {
"@type": "Review",
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"author": { "@type": "Person", "name": "Real customer, with consent" },
"reviewBody": "Fed from the live Google Business Profile /
Podium review stream — never hand-written."
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9",
"reviewCount": "187"
}
}
</script>
Plus suburb-level service pages, a Google Business Profile wired to the review flow, and Arborist-adjacent category signals (Google's taxonomy uses "Tree service").
What would change for the real client
- AroFlo — job cards, scheduling and SWMS (working-at-heights compliance lives or dies on the safety paperwork); the form would create an AroFlo lead directly.
- SafetyCulture — pre-climb audits and toolbox records, linked from each job card.
- Xero — invoicing and deposits, reconciled against AroFlo.
- NearMap — canopy imagery for desktop quoting: half the "how much is my tree" calls can be scoped from current aerials before the site visit.
- Geotab — chipper-truck tracking feeding an honest "we're in your street" mulch offer and live ETA SMS.
- Council permit workflows — templated significant-tree register checks and application forms per LGA (Kalamunda, Mundaring, Gosnells), tracked per job.
- Podium — the review stream that replaces this page's demo copy, and the source feeding the real schema above.
- Their photography, their real licences and ABN, and the estimator recalibrated from their last 12 months of quoted jobs.
Iteration log
Drove everything headless; the screenshots caught what the asserts couldn't.
A 33-check puppeteer run drove every chip, both toggles, the FAQ, the estimator→form handoff, an empty submit on a fresh load (3 fields flagged) and a filled submit (confirmation in the required lexicon) — with all seven pricing scenarios asserted against an independently reimplemented oracle. One real failure: at 375×667 the primary CTA sat 2px under the fold and the trust line ~166px below it. Compressed the hero art (150→104px), lowered the h1 clamp floor, trimmed the sub-copy to one sentence and made the CTAs full-width — h1, both CTAs and the trust signal now all land above the fold. The screenshot review then caught two defects every state assert sailed past: the stump-grind zoom magnified two in-scene mono labels into giant overlapping text (label deleted — the fact already lives in the estimate card; ground access marks now hide inside the zoom), and the Sapience band's amber button label washed out because .sapience a out-specified .btn-amber (explicit colour override added).
Made the zoom honest and the scene self-measuring.
The stump zoom was real but useless: a fixed ×1.95 against a ×0.62 medium tree netted ×1.2 and read as nothing. Normalised it to the stump (scale = 2.6 ÷ sizeFactor) so the base reads close-up at every size. Densified the hero canopy clusters (×1.25–1.3 scale on the position groups), moved the reduction line's draw-in to the scene's first viewport entry, added the price-pop micro-interaction on the estimate card, and put a measured drawn-height readout in the scene caption (≈15 m / ≈9.5 m / ≈4.6 m at 22 px per metre — each inside its chip's band). Second-read detail: a red-tailed black cockatoo lands on the large tree only.
Keyboard path, icon semantics, one ornament removed.
Added keyboard drives to the harness — Enter and Space on chips, Enter on FAQ summaries — all passing (native buttons and details/summary, nothing custom to break). Fixed an icon semantics slip: the "$20M insured" trust item wore a left-arrow icon; now a certificate. Chanel rule: the hero rope's figure-8 knot loop read as a stray ring at hero size — removed; the plain rope line is stronger. Re-verified 375px overflow (zero offenders), reduced-motion (arc settled, hero visible, sway and pops off), the 7-second settle screenshot, and zero console errors: 37/37 checks. Final copy read done against the shipped numbers — the grid, FAQ, estimator and this guide all agree on $280/$380/$650/$780/$2,800 and the measured $1,170.