Generative Assets · Industry Demos · how it was made
How the Kestrel Aerial Mapping demo was built
Kestrel Aerial Mapping is a fictional Canning Vale drone survey and aerial mapping practice — orthomosaics, DSM and contours to AHD, 3D reality models and roof inspections for builders, civil contractors, strata managers and councils across Perth and the regions. The page exists for one reader: the person with a site to map who wants the deliverable, the hectares, the detail, the ground control and the travel priced honestly, to the whole dollar, before they ring. Its single job is a flight request with that scenario already attached.
The Site Mapper
The signature element is a drawn SVG plan-view site sheet: an irregular survey boundary on a sand-brown fill, amber lawnmower flight lines across it, and a drone glyph tracing them with a faint swath trail. Every control redraws the sheet honestly and reprices the flight from the pinned anchors:
- Area 1–50 ha scales the boundary at side ∝ √hectares in sheet units — a 7-vertex unit polygon whose shoelace area is the honest link between hectares and drawn size, so the 100 m scale bar is a constant 61 sheet units at every area and a 1 ha lot really is 100 m across. Every value 1–50 is drawable; there is no drawn cap. The number of drawn passes is
min(3 + ⌊ha ÷ 4⌋, 15)(3 at 1 ha, 5 at 10 ha, 9 at 25 ha, the 15-pass ceiling at exactly 48–50 ha) and the sheet's legend prints that count as "n passes" — a drawing of the plan, not a billed quantity. - Deliverable chip redresses the plan: orthomosaic draws the flight lines only; DSM & contours adds nested contour loops clipped to the boundary with a spot-height label; the 3D reality model adds a cross-hatched second flight pattern at 90° (lighter, dashed) and oblique tick marks along the passes; roof & asset inspection swaps the site for a cluster of drawn hip roofs (the structures stepper's count, 1–6, all drawable) with an amber orbit around each, and the drone flies orbit to orbit.
- Detail chip: high detail draws the half-spacing infill passes between the pinned primary passes — lighter and dashed, so the legend's pass count stays the pinned formula while the sheet visibly tightens; ground control draws crosshair targets at the boundary corners (sized with the plan so a 1 ha lot isn't buried under its own corners) and a "GCP ×7 · AHD" tag; beyond metro draws a road leaving the sheet to the west with a distance tick and "← travel by the km".
- The price badge is drawn as a survey control-point plate — a field-sheet card with an amber edge and a brass disc in the corner. Two lines always: the total (or the quoted-state form) and "flown and delivered in about <days> business days" (3 / 5 / 7 / 2 by deliverable). On-scene upper-left over the sheet margin at ≥641 px (the subject is composed to the right of it at every area and structure count — asserted, never over the polygon, the roofs or the drone), docked directly beneath the plan inside the card at ≤640 px.
- The contours note — "contours without ground control are relative, not AHD — most councils and engineers want ground control, +$350 here" (the figure is derived from the GCP anchor, never hard-coded; short form ≤640 px "contours need ground control for AHD — +$350") — appears on DSM & contours with ground control OFF and nowhere else; toggling ground control ON removes it and the measured delta equals the note's figure.
- Inspection disables area, detail and ground control with their reasons on-page ("Inspections are priced per structure." / "Inspections are always shot at full detail — included." / "No ground control needed for an inspection."), forces ground control OFF for pricing and remembers the prior state; the mapping chips disable the structures stepper ("Mapping is priced by the hectare."). Each remembered value is RESTORED the moment a deliverable that uses the control is re-selected; because the control that could change a remembered value is disabled while another deliverable holds it, the restore memory can never be invalidated by an explicit change — the W41 rule holds trivially, and we say so here.
Pinned anchors (GST inclusive; flight, processing and delivery; metro Perth travel included)
| Deliverable | Base | Per hectare | Days | Floor (1 ha, standard, no GCP) |
|---|---|---|---|---|
| Orthomosaic map | $900 | $40 / ha | 3 | $940 |
| Orthomosaic + DSM & contours | $1,200 | $60 / ha | 5 | $1,260 |
| 3D reality model | $1,500 | $80 / ha | 7 | $1,580 |
| Roof & asset inspection | $550 first structure | $250 each extra structure | 2 | $550 |
High detail (1.5 cm GSD) is +$300 flat and ground control to AHD is +$350 flat, both on the three mapping deliverables only; the per-hectare rate multiplies the hectares, the extra-structure rate multiplies (structures − 1), and base, detail and ground control are flat. A site beyond metro Perth turns the total into the quoted-state form "<total> + travel, quoted by the kilometre" wherever the total prints — badge, ledger and the screen-reader mirror — never a bare "quoted". There is no empty state: a deliverable is always selected and both steppers have floors of 1. Every rate is a whole dollar and every count is a whole unit, so no total ever needs rounding.
Worked examples measured from the running page
| Scenario | Arithmetic | Total | Days | Note | Passes |
|---|---|---|---|---|---|
| Rest state — DSM & contours, 10 ha, standard, GCP on, metro | 1,200 + 600 + 350 | $2,150 | 5 | absent | 5 |
| Orthomosaic, 1 ha, standard, GCP off (grid floor) | 900 + 40 | $940 | 3 | absent | 3 |
| DSM, 1 ha, standard, GCP off | 1,200 + 60 | $1,260 | 5 | present | 3 |
| 3D, 1 ha, standard, GCP off | 1,500 + 80 | $1,580 | 7 | absent | 3 |
| Inspection, 1 structure | 550 | $550 | 2 | absent | — |
| DSM, 10 ha, standard, GCP off → GCP on | 1,200 + 600 → + 350 | $1,800 → $2,150 | 5 | present → absent (delta 350 = the note's figure) | 5 |
| 3D, 25 ha, high detail, GCP on | 1,500 + 2,000 + 300 + 350 | $4,150 | 7 | absent | 9 |
| Orthomosaic, 50 ha, high detail, GCP on | 900 + 2,000 + 300 + 350 | $3,550 | 3 | absent | 15 (ceiling) |
| Inspection, 4 structures | 550 + 750 | $1,300 | 2 | absent; area, detail, GCP disabled with reasons | — |
| Restore: ortho 12 ha GCP off → inspection 4 → ortho | 900 + 480 → 550 + 750 → restored 12 ha | $1,380 → $1,300 → $1,380 | 3 → 2 → 3 | absent | 6 → — → 6 |
| Quoted: DSM 10 ha GCP on, beyond metro | 2,150 + travel | $2,150 + travel, quoted by the kilometre | 5 | absent | 5 |
| Rapid-fire: area 10, GCP on, ortho → 3D → inspection → DSM in one evaluate | restored 10 ha | $2,150 | 5 | absent; one flight loop after settle | 5 |
Every worked figure, the four cheapest-output floors ($940 / $1,260 / $1,580 / $550, equal to the services grid), the note's three-surface presence and absence, the quoted-state string on all three surfaces and 36 random control vectors were cross-checked against an oracle reimplemented from the anchors in the verification harness — not from the page's own code. The final pass ran 597 assertions (575 on the site, 22 on this guide), all green.
Palette — argued from a high Perth sky
Pale sky ground, slate ink like a controller's housing, survey teal for the CTAs and links, amber for the flight lines and every mark, and the sand-brown of a site under a flight plan doing real work in the scene. Contrast ratios below were computed with WCAG arithmetic from the shipped tokens in Pass 1 (role, hex and ratio from the same script row).
Every spec figure measured within 0.1 of its computed hypothesis on the shipped tokens (slate 13.1 / 14.6, white-on-teal 5.8 / hover 7.5, teal-on-sky 5.1, amber-ink 5.3 / 5.9) — no token moved. The sub-ink and the map-water pair were minted by the builder and measured before use; sheet labels (pass legend, scale bar, GCP and spot-height tags) are slate with a sheet-coloured halo so they hold their ratio where they cross the earth fill.
Type
The display moment is the rest-state line set over the plan — "$2,150 · 10 HA · DSM + CONTOURS · 5 DAYS" — rebuilt from state on every change, so the figure is always the live total; the rest-state total is the measured $2,150, and the tokens are joined with non-breaking spaces so a wrap never strands a dot or a unit at a line end.
Techniques
- Procedural SVG sheet, no libraries. A graph-paper pattern is the only static layer; the boundary, contours, flight pattern, targets, road, roofs, orbits, furniture and the live layer are rebuilt on every state change. Flight lines are the horizontal crossings of the polygon at n evenly spaced heights, each overshooting the boundary for the turn, joined into one serpentine path with cubic turns; the 90° pattern is the vertical crossings at the same spacing; contours are six deformed loops (three sine terms) clipped by the boundary polygon.
- Zoom-to-fit frame. The boundary is drawn at side ∝ √ha in sheet units — the 100 m bar is a constant 61 units — and the sheet's viewBox fits the subject between a 420-unit floor and the full 1080-unit sheet (desktop), tighter still at ≤640 px (the W41 phone-width crop). Growing hectares read as the polygon growing and the scale bar shrinking, exactly as a plan viewer behaves; the inspection sheet is its own scale (a 30 m roof, a 20 m bar). Labels and furniture are sized from the rendered pixels-per-unit so they hold 12–13 px at any zoom, and the drone glyph clamps between 9 and 16 units of arm.
- Dual-speed redraw (W21). First paint staggers each drawn part at 26 ms (1.4 s cap); every later change redraws at 10 ms per part with a 500 ms cap via a
firstDrawflag. Parts animate opacity only — never a property they also set as an SVG attribute. - Token-invalidated flight loop (W25). The drone rides the flight path with
getPointAtLengthat 95 units per second, heading from the path tangent, the swath trail a wide translucent stroke of the same path whose dash array grows with progress. One requestAnimationFrame loop per scene; its token is bumped in every control handler before the state swap, the loop exits on its next frame and the rebuilt sheet starts a fresh one — the probe'sloopscount settles back to exactly one after two rapid-fire bursts. Delta time is clamped at zero and capped at 50 ms (W29); the loop idles while the tab is hidden; the drone and the flight lines are always at full opacity, so the scene is visibly alive at any capture instant. - Control-point plate. An HTML badge positioned over the sheet's upper-left margin by CSS (no measurement needed — the subject is composed to the right of it at every state, and the harness asserts the plate never intersects the polygon, the roofs or the drone at 641, 700, 820, 1000 and 1200 px); at ≤640 px it docks beneath the plan in flow. The brass disc pulses once on each change after the first draw.
- Reduced motion. CSS media query plus a
matchMediacheck: no loop starts, the drone is parked mid-path with its swath drawn to there, the entrance transitions, the hero's rise and the disc pulse are off; controls still compute. - State probe.
window.__dronesurveycarries deliverable, hectares, structures, detail (chosen and effective), ground control (effective and remembered), beyond-metro, every ledger line, the total and its text form, days, the note and its two forms, the drawn pass count, the disabled and forced flags with their reasons,loops,progressand asettledflag — QA gates on state, never on seconds.
Conversion decisions
- Above the fold at 375 px: business name, "Drone survey and aerial mapping across Perth — orthomosaics, contours to AHD, 3D models and roof inspections, flown and delivered in days", Book a flight + Call (08) 9000 0368, and the CASA ReOC / RTK / $20M trust line — all inside the first viewport, measured.
- Book vs call: a flight is planned work (airspace, weather window, ground control), so the primary CTA is "Book a flight" with the phone a visible ghost button; on phones a sticky bar carries Call now + Book a flight above the thumb.
- The Mapper feeds the form. Deliverable, area or structures, detail, ground control, travel, the total and the days line pre-fill the flight textarea; "Book this flight" refreshes it and focuses the name field. Form fields are the ones a survey practice needs to plan a flight: name, mobile, site suburb (the airspace check starts there), sector (civil & construction / property & development / strata & asset / government & utilities — it sets who the deliverables go to) and the details block.
- Honest floors and declarations. The services grid's "from" prices are the Mapper's cheapest outputs — $940 / $1,260 / $1,580 / $550; metro travel is declared "included" on the plate, in the ledger and in the mirror; beyond the metro the total keeps its priced part and declares the travel beside it; CASA approvals are named as something we handle at no charge that can add days.
- Local confirmation, no fake network. Empty submit flags the required fields inline, moves focus to the first and keeps the confirmation hidden; a valid submit shows the designed panel ("Thanks — flight request received. We'd call you back within one business day…") naming the person, the site suburb and the estimate, clearly marked as a demonstration.
Local SEO we'd implement for the real business
The live page carries only WebPage, WebSite and BreadcrumbList structured data naming it a demonstration — a fictional practice must not mark itself up as a real one. For the real client we would ship the block below. A drone survey practice is a professional service, not a store, so the top-level type is ProfessionalService (an actual schema.org organisation subtype) with the offerings named through hasOfferCatalog and knowsAbout. Real reviews would be pulled from Google Business Profile and marked up only with the reviewer's consent.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ProfessionalService",
"name": "Kestrel Aerial Mapping",
"description": "Drone survey and aerial mapping from Canning Vale — orthomosaics, DSM and contours to AHD, 3D reality models and roof inspections across Perth and regional WA.",
"url": "https://www.example-kestrel.com.au/",
"telephone": "+61 8 9000 0368",
"image": "https://www.example-kestrel.com.au/site-sheet.jpg",
"priceRange": "$$",
"address": {
"@type": "PostalAddress",
"addressLocality": "Canning Vale",
"addressRegion": "WA",
"postalCode": "6155",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -32.07, "longitude": 115.92 },
"areaServed": ["Perth", "Forrestdale", "Baldivis", "Welshpool", "Midland", "Wangara", "Rockingham", "Joondalup", "Mundaring"],
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"], "opens": "07:00", "closes": "17:00" }
],
"knowsAbout": ["drone survey", "aerial mapping", "orthomosaic", "digital surface model", "contour survey", "ground control points", "3D reality model", "roof inspection", "stockpile volumes"],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Drone survey services",
"itemListElement": [
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Orthomosaic map" }, "priceSpecification": { "@type": "PriceSpecification", "price": "940", "priceCurrency": "AUD", "description": "from, 1 ha, 3 cm GSD" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "DSM and contour survey" }, "priceSpecification": { "@type": "PriceSpecification", "price": "1260", "priceCurrency": "AUD", "description": "from, 1 ha" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "3D reality model" }, "priceSpecification": { "@type": "PriceSpecification", "price": "1580", "priceCurrency": "AUD", "description": "from, 1 ha" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Roof and asset inspection" }, "priceSpecification": { "@type": "PriceSpecification", "price": "550", "priceCurrency": "AUD", "description": "first structure" } }
]
},
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "64" },
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "Real customer, with consent" },
"datePublished": "2026-05-02",
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "Pulled from the live Google Business Profile feed — never hand-written."
}
]
}
</script>
Alongside the schema: a Google Business Profile with the hangar pinned, "drone survey Perth" / "aerial mapping Perth" / "drone roof inspection Perth" / "contour survey Baldivis" as the page's core phrases with the suburbs above as secondary, NAP consistency across the surveying and construction directories, and a reviews feed that updates without anyone touching the page.
What changes for the real client
- Processing and client share links: DroneDeploy or Pix4D for the photogrammetry pipeline and the client's ortho / DSM / model share links — the Site Mapper's scenario becomes the flight plan's parameters, not a textarea.
- Flight logs and CASA compliance: a flight-log and compliance tool (the kind that holds the ReOC operations manual, pilot RePLs, aircraft logs and the airspace approvals) wired behind the booking so every flight is recorded the day it's flown.
- Xero for the invoice the moment the deliverables are shared; the estimate maps line-for-line onto the invoice.
- A progress-flight subscription portal behind the monthly flights — the same plan, the same control, a time series the claims team scrubs through.
- The practice's own orthos, models and inspection sets in place of the drawn sheet, a Google reviews feed, the real ABN, ReOC and insurance certificates, and the real phone number in place of the reserved pattern.
Iteration log
- Pass 1 — Craft. Contrast measured from the shipped tokens with WCAG arithmetic (29 pairs): every spec figure held within 0.1 and no token moved; the builder-minted sub-ink and map-water pair were measured before use. The first build drew the sheet at a fixed viewBox, which left a 10 ha boundary at ~170 px and a 1 ha lot at 37 px with 8 px labels — the frame now zooms to fit the subject between a 420-unit floor and the full sheet, labels are sized from the rendered pixels-per-unit (13 px at any zoom), the drone glyph clamps 9–16 units and the corner targets scale with the plan. The inspection sheet's 100 m bar implied 216 m roofs — it now carries its own honest 20 m bar for 30 m roofs. The beyond-metro road left the sheet to the east, where at 50 ha it crossed the boundary and its label — it now leaves to the west under the plate, and the phone crop adds a verge for it. The docked plate's brass disc was painting at the scene's corner (an absolute pseudo-element resolving to the wrong containing block) — the docked plate is now
position: relative. Map: the Canning Vale label was running into the Forrestdale marker — re-anchored to the west of the star. The display line's tokens now use non-breaking spaces; the plate eyebrow shortened to "Flight estimate". Drove: rest + every worked example + 36 oracle vectors + restore + quoted + rapid-fire + form empty/filled + 375 — 595 of 597 asserts green; the two failures were this guide's own masthead overflowing 375 px by 27 px (wordmark plus two nav buttons), fixed by hiding the wordmark text below 520 px. - Pass 2 — Depth. The spot-height label inside the contours reads "RL 24.0 AHD" with ground control on and "RL 24.0 rel." with it off — an honest second-read detail that mirrors the note. High detail now draws the half-spacing infill passes (lighter, dashed) between the pinned primary passes, so the sheet visibly tightens while the legend keeps the pinned count; the 3D model gained oblique tick marks along every pass beside its 90° cross pattern; the roofs gained a lean-to on alternate structures and a plant unit so a cluster reads as real buildings. The drone's heading follows the path tangent and its swath width follows its scale. One micro-interaction: the plate's brass disc pulses once on every change after the first draw (off under reduced motion). Pass 2 drove the restore sequence (ortho 12 ha → inspection 4 → ortho, area restored to 12; DSM high GCP → inspection → DSM, detail and GCP restored), the GCP delta against the note's figure, the quoted-state string on all three surfaces with the no-bare-"quoted" sweep, two rapid-fire bursts (one loop after each), the 1000 px mid-width band with the FULL note form, and the plate-clear-of-subject geometry at 641 / 700 / 820 / 1000 / 1200 at 50 ha and 6 structures — 597 of 597 green. The beyond-metro road's label was still striking the road itself and the "structure 4" tag on the phone crop — moved beneath the road at the frame's edge.
- Pass 3 — Hardening. 375: masthead wordmark right edge vs call button left edge compared explicitly (no collision), h1 + primary CTA + trust line inside the first 740 px, sticky bar fixed within the bottom 140 px with 48 px tap targets and no backdrop-filter, scrollWidth 375 with zero per-element offenders (the sheet's grid rectangle was the one offender — it now follows the viewBox instead of over-painting it), body 17 px, the plate docked beneath the plan with the SHORT note form while the ledger and mirror keep the full template; 640 docks and 641 sits on-scene. Reduced motion: no loop, drone parked mid-path, identical frames 1.3 s apart, controls still compute. The v-flag form patterns compile in the browser; keyboard Enter/Space drive chips and toggles; focus rings render. Chanel rule: the hero motto no longer repeats the trust line's "metro Perth & the regions" — it carries the tagline and the founding year only. Three-width native screenshots (375 / 1000 / 1200) were swept for label collisions over the pass legend, the corner targets, the spot height, the road tag and the plate. The phone crop's floor was loosened (280 × 270 units) so a 1 ha lot fills more of a 375 px sheet. Final copy read in Australian English. Final run: 597 of 597 asserts across both pages, zero console errors or warnings.
Two builder calls worth flagging for the wave sweep: (1) "the detail chip halves the flight-line spacing on high detail" is shipped as interleaved infill passes drawn lighter and dashed between the pinned primary passes — the legend's pass count stays min(3 + ⌊ha ÷ 4⌋, 15) as pinned, and the infill is a drawing, not a count; (2) the desktop frame zooms to fit the subject (420-unit floor, 1080-unit ceiling) while the boundary stays at side ∝ √ha in sheet units and the 100 m bar stays 61 units — a presentation choice in the W41 crop family, documented here so the growth-with-hectares reads as the plan viewer's zoom plus the constant scale bar rather than a fixed frame.
This is a demonstration build by Sapience Analytics. Want one pointed at your customers?