Generative Assets · Industry Demos · how it was made
How the Halewood Migration demo was built
Halewood Migration is a fictional firm of registered migration agents on St Georges Terrace in Perth — skilled, employer sponsored, partner, student and business innovation visas, for people already in WA and for the employers bringing them here. The page exists for the Malaga fabricator whose best welder is on a 482 that expires in November, the WA Health nurse going 482 to 186, and the Como couple lodging an 820. Its single job is a consultation booking with the visa, the service level and the people on the application already priced — professional fees to the whole dollar, government charges declared and never marked up.
The Pathway Planner
The signature is a lodgement sheet drawn in SVG: an open passport at the left with a gold crest and a green subclass stamp, small figure marks for the people on the file, and a ruled route running left to right with a numbered roundel at each stage of the visa. Every control redraws the sheet and reprices the file from the pinned anchors.
- The visa chip redraws the stages. Skilled draws five roundels (skills assessment → EOI in SkillSelect → invitation → lodgement → decision); employer sponsored, partner and student draw four; business innovation draws five. The subclass stamp on the passport's right page changes with it —
189 · 190 · 491,482 · 186,820 · 801,500,188. - The service-level chip inks the route. Full representation stamps every stage in approval green except the last, which stays an unstamped navy outline with the caption "not stamped — nobody can promise this one" — we never draw an approval we can't promise. Document review inks the first roundel only and dashes the rest under a "we check, you lodge" bracket; EOI & skills support inks the first two under "you lodge from here — we hand you the file". A segment is inked only when we actually carry the file across it, so the handover arrow after a document review is dashed grey, not green.
- The partner toggle and the children stepper add figure marks above the route. The drawn cap is the enumerated file — you, your partner and up to four children, so six marks — and every value the controls can reach is drawable, so the cap is never a truncation. The primary is navy solid, the partner green solid, children green outline. On a partner visa the partner mark turns gold outline and the caption reads "partner (sponsor)", because on that visa your partner is the sponsor, not an applicant.
- A dashed leader ties the people to the first stage of their route — the second-read detail that makes the sheet read as one document rather than two illustrations. The other one is the faint
FILE HM‑2026‑0371reference stamped in the sheet's corner. - A slow loop breathes an ink bloom around the most recently stamped roundel (opacity floor 0.55, so the signature is visibly alive at any capture instant) and drifts a fine paper grain across the sheet. Reduced motion parks the bloom at full and the grain still. Chip swaps redraw snappy — 26 ms stagger capped at 1.4 s on the first draw, 11 ms capped at 520 ms after — and the bloom loop is token-invalidated in the handler, before the state swap.
- The price badge is drawn as a lodgement stamp card with a gold foil edge: total, the visa and head count, the service line (always present, pinned per service level), and either the family-loading note or the price-neutral declaration. It sits on the sheet's reserved upper-right corner at ≥641 px and docks directly beneath the sheet at ≤640 px.
Pinned anchors — professional fees, GST inclusive, whole dollars
| Visa | Subclasses | Full representation | Stages drawn | Document review | EOI & skills support |
|---|---|---|---|---|---|
| Skilled points-tested | 189 · 190 · 491 | $4,200 | 5 | $850 | $1,900 |
| Employer sponsored | 482 · 186 | $5,400 | 4 | $850 | skilled only |
| Partner | 820 · 801 | $5,800 | 4 | $850 | skilled only |
| Student | 500 | $1,600 | 4 | $850 | skilled only |
| Business innovation | 188 | $14,500 | 5 | $850 | skilled only |
| Partner on the application | full representation only | +$900 | a figure mark | $0 | $0 |
| Each child on the application | full representation only | +$450 | a figure mark | $0 | $0 |
The child loading multiplies the actual child count; the partner loading is flat; the visa fee is flat per application and nothing multiplies by the visa. Every rate is a whole dollar and every stepper grid is a whole unit, so no total in the model can be non-integer — the whole-dollar display is arithmetic, not rounding. There is no empty state: a visa chip and a service-level chip are always selected, and the children stepper floors at zero.
Worked examples, measured from the running page
Each row was driven with the full control vector set explicitly — visa, service level, partner and children — and checked against an oracle that reimplements the model independently. The exhaustive sweep covers all 110 reachable cells (5 visas × 3 service levels, skipping EOI on non-skilled visas, × 2 partner states × 5 child counts).
| Visa | Service level | Partner | Children | Measured total | Family note / declaration |
|---|---|---|---|---|---|
| Skilled (rest state) | Full representation | on | 2 | $6,000 | note: includes $1,800 for your partner and 2 children on the same application |
| Student | Full representation | off | 0 | $1,600 | note absent |
| Partner | Full representation | disabled | 1 | $6,250 | note: includes $450 for 1 child on the same application |
| Any visa | Document review | on | 3 | $850 | declaration: $0 — one review fee, whatever the family size |
| Skilled | EOI & skills support | on | 2 | $1,900 | declaration: $0 — your partner and children go on the same EOI |
| Business innovation | Full representation | on | 4 | $17,200 | note: includes $2,700 for your partner and 4 children on the same application |
| Employer sponsored | Full representation | off | 3 | $6,750 | note: includes $1,350 for 3 children on the same application |
| Skilled | Full representation | on | 0 | $5,100 | note: includes $900 for your partner on the same application |
The cheapest output of each branch is the corresponding "from" figure in the fees grid — document review $850, EOI & skills support $1,900, student $1,600, skilled $4,200, employer sponsored $5,400, partner $5,800, business innovation $14,500 — and the overall cheapest output, $850, is the floor of the grid. The page cannot argue with itself.
Locks, forces and remembered values
- EOI is skilled-only. On any other visa the chip is disabled with the reason "skilled visas only" on the chip and in full beneath the chip row. If EOI is selected when a non-skilled visa is chipped, the service level is forced to full representation and EOI is remembered; chipping skilled again restores it. Measured: skilled + EOI $1,900 → partner visa forces full representation and reads $5,800 → skilled restores EOI and reads $1,900.
- The memory is cleared by an explicit service-level change while forced. Measured: skilled + EOI → student (forced to full, EOI remembered) → deliberately chip document review (memory cleared) → chip skilled → the service level stays document review, $850.
- The partner toggle is disabled on a partner visa with the reason "on a partner visa your partner is the sponsor, not an applicant". Its on/off value is remembered and restored on any other visa — and because the toggle is inert while disabled, the only thing that could clear the memory is impossible in that state, so it always survives the lock. The toggle keeps
aria-pressedon the remembered value while disabled, so the restore is visible rather than silent; the probe exposes the remembered value and the applied value separately. - The children stepper stays enabled on document review and EOI and says why: children still come across to the enquiry form, they just don't change that fee. The partner toggle behaves the same way on those two service levels — a visible response with an honest price-neutral declaration rather than a control that silently no-ops.
What prints wherever the total prints
Two declarations are always on: the Department of Home Affairs charges line and the payment split. They appear beside the total in the ledger, in the plain-text mirror screen readers get, and as full sentences directly beneath the sheet; below 641 px each swaps to its pinned short form ("DHA charges at cost", "half on engagement, half at lodgement"), and the family note swaps to "+$1,800 family". The ledger and the mirror always carry the full template at every width. The confirmation panel repeats the government-charges line, because that is where a client would otherwise assume the quoted figure was everything.
Palette — bone lodgement paper, a navy passport, a green approval stamp, gold foil
Every ratio below was measured in Pass 1 with WCAG arithmetic against the tokens the page actually ships, read from the live custom properties in the browser, not from the spec.
The service-area map obeys the same rule: its suburb labels are set in the body navy with a ground-coloured halo (paint-order: stroke) and measure 10.79:1 over the ocean fill and 8.06:1 where a label crosses the Swan River band; the "St Georges Tce office" and "Regional WA by video" labels use the green ink at 6.95:1, and the rotated "Indian Ocean" label uses the slate at 5.68:1 against the ocean fill. The greyed, not-yet-ours stage labels on the sheet are #6E6A5C at exactly 5.00:1. The error ink #9A2A1A measures 7.72:1 on white, and the form's placeholder ink #646C82 5.02:1 on the field fill — placeholders are not content, but a demo page that shows a worked example in the placeholder should let you read it. The footer's body and quiet inks measure 9.93:1 and 7.62:1 on the navy.
This palette is held off the cream-plus-terracotta AI default by the navy and by a green rather than an orange accent, and off the broadsheet default by having no hairline column rules anywhere — the page's structure is the drawn pathway.
Type
Techniques
- One inline SVG scene, two layouts. The sheet is built from scratch on every state change into a
<g>that is cleared and repopulated; a separate background group holds the paper, grain, punched holes and header, redrawn only when the layout changes. Above 640 px the route runs left to right in a780 × 520unit box; at or below 640 px it stacks down a380 × 664box, because a five-stage horizontal route at ~315 px of drawn width puts the stage labels under 6 px. Same data, same anchors, same stamps — a different composition, chosen bymatchMediaand swapped on resize. - Scale-compensated type inside a scaled group. The passport is drawn once in local units and placed with
translate() scale() rotate(); the type inside it sets its font size as base ÷ the group's scale, so the "PASSPORT" line and the subclass stamp stay the same drawn size in both layouts instead of shrinking with the booklet. - Entrance choreography at two speeds. Every drawn part gets a
--iindex and a CSS opacity transition delayed by--i × --stag. The first draw uses a 26 ms stagger capped at 1.4 s; every subsequent redraw uses 11 ms capped at 520 ms, so chipping a visa reads as a snap rather than a replay. The probe'ssettledflag flips when the cap elapses, and the verification harness gates every screenshot on it. - Token-invalidated animation. The bloom loop closes over a token captured at start; every control handler bumps the token before the state swap, so a burst of clicks with no settle between them leaves exactly one loop running against the current scene. The rAF delta is clamped at zero as well as capped (
min(max(now − last, 0)/1000, 0.05)) so a vsync timestamp that precedes the scheduling call can't drive a negative radius. - No raster anywhere. The passport, the crest, the stamps, the figure marks, the route and the service-area map are all drawn geometry; the paper grain is 130 seeded circles at 5.5 % opacity, spawned inside a 20-unit inset so the ±12-unit drift never pokes a dot outside the viewBox.
- Local state only. No network, no storage, no analytics.
window.__migrationexposes the scenario, every computed figure, the lock and memory state, the three declaration surfaces and asettledflag, plus aset()helper that routes through the same handlers a user's clicks do.
Conversion decisions
- Above the fold at 375 px: the business name, "Registered migration agents in Perth — skilled, employer sponsored, partner and student visas", a Book a consult button and a Call (08) 9000 0371 button, and three trust signals (registered agent MARN, fees in writing, Perth CBD since 2009) — all inside the first viewport, measured at 743 px of 812. The masthead was measured explicitly: the wordmark's right edge sits at 226 px against the call button's left edge at 234 px, with the Consult button ending at 361 px.
- Book, then call. Migration work is almost never an emergency, so the primary CTA is a consult booking and the phone is the ghost button beside it — but a deadline is the trade's real urgency, so the promise box and the form copy both say "ring us as well if your visa expires inside sixty days". On phones a sticky bar carries Call now and Book a consult above the thumb.
- The Planner feeds the form. Visa, service level, partner, children and the quoted fee pre-fill the enquiry textarea, ending with an open "Where I am up to:" prompt; "Book this pathway" refreshes it and focuses the name field. The five fields are what a migration agent needs before a first consult: name, mobile, where you are (which changes how you meet, not the fee), nationality and current visa, and the scenario block with a nudge to disclose refusal history.
- Honest floors, honest silences. The fees grid's "from" prices are the Planner's cheapest outputs for each branch. The Department's charges are never estimated on the page — they are set by government, they move on 1 July, and a stale figure would be the dishonest choice — so the page carries the at-cost declaration wherever the total appears and promises the current schedule at the consult. The decision roundel is drawn unstamped and captioned, and the FAQ says plainly that nobody may guarantee a visa.
- Local confirmation, no fake network. An empty submit flags every required field inline, sets
aria-invalid, and leaves the confirmation panel hidden; a valid submit reveals the designed panel naming the client, the visa, the service level, the head count and the fee, repeating the government-charges declaration and saying plainly that this is a demonstration page and nothing was sent anywhere. - Every SVG surface has a plain-text twin. A visually-hidden live region mirrors the whole ledger in sentences, including the note, both always-on declarations, the lock reasons and the total — so a screen-reader user gets the same argument as the sheet, at the same moment.
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 agency must not mark itself up as a real one, and fictional reviews must never become structured review data. For the real client we would ship the block below. schema.org has no migration-agent subtype, so the top-level type is ProfessionalService — an actual organisation type in the LocalBusiness family — with the specialty named through additionalType, knowsAbout and a hasOfferCatalog. Reviews would come from the live Google Business Profile feed, with the client's consent, never hand-written.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ProfessionalService",
"additionalType": "https://www.wikidata.org/wiki/Q17102529",
"name": "Halewood Migration",
"description": "Registered migration agents in Perth — skilled, employer sponsored, partner, student and business innovation visas.",
"url": "https://www.example-halewood.com.au/",
"telephone": "+61 8 9000 0371",
"image": "https://www.example-halewood.com.au/office.jpg",
"priceRange": "$$$",
"address": {
"@type": "PostalAddress",
"streetAddress": "Level 9, 000 St Georges Terrace",
"addressLocality": "Perth",
"addressRegion": "WA",
"postalCode": "6000",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -31.955, "longitude": 115.856 },
"areaServed": ["Perth", "Joondalup", "Malaga", "Midland", "Victoria Park", "Fremantle", "Rockingham", "Mandurah", "Western Australia"],
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"], "opens": "08:30", "closes": "17:30" }
],
"knowsAbout": ["skilled migration", "employer sponsored visas", "partner visas", "student visas", "business innovation visas", "skills assessment", "SkillSelect expressions of interest"],
"hasCredential": {
"@type": "EducationalOccupationalCredential",
"credentialCategory": "Registered Migration Agent",
"recognizedBy": { "@type": "GovernmentOrganization", "name": "Office of the Migration Agents Registration Authority" },
"identifier": "MARN 0000000"
},
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Migration services",
"itemListElement": [
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Document review" }, "priceSpecification": { "@type": "PriceSpecification", "price": "850", "priceCurrency": "AUD", "description": "flat professional fee, any visa, any family size" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "EOI & skills-assessment support" }, "priceSpecification": { "@type": "PriceSpecification", "price": "1900", "priceCurrency": "AUD", "description": "flat professional fee, skilled visas" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Skilled points-tested visa — full representation" }, "priceSpecification": { "@type": "PriceSpecification", "price": "4200", "priceCurrency": "AUD", "description": "from; Department of Home Affairs charges at cost" } },
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Partner visa (820/801) — full representation" }, "priceSpecification": { "@type": "PriceSpecification", "price": "5800", "priceCurrency": "AUD", "description": "from; Department of Home Affairs charges at cost" } }
]
},
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "168" },
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "Real client, with consent" },
"datePublished": "2026-06-14",
"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 St Georges Terrace suite pinned and the consult link wired; "registered migration agent Perth", "482 visa Perth", "partner visa Perth" and "skilled visa WA" as the page's core phrases with the suburbs above as secondary; NAP consistency across the professional and community directories that migration clients actually search; and a reviews feed that updates without anyone touching the page. We would also publish the Department's current charge schedule as a dated page rather than baking figures into the landing copy, so the honest "at cost" promise stays true after 1 July.
What changes for the real client
- Case management: Migration Manager (the file-and-checklist system most Australian agencies already run) behind the form, so a submitted scenario opens a real matter with the right document checklist attached instead of landing in an inbox. Their own key dates feed the 801 and 482-expiry diary rather than a promise in the copy.
- Engagement letters: DocuSign for the client agreement and the Code of Conduct consumer guide, sent the moment the consult is booked — which is what actually turns the quoted fee on this page into a signed scope.
- Payments: Stripe for the staged fee — half on engagement, half at lodgement — with the Department's charges kept off the invoice entirely and paid by the client at cost, so the "we don't mark them up" claim is provable in the accounting, not just in the copy. Xero behind it.
- Pipeline: HubSpot for the enquiry pipeline, so a student visa enquiry in March is still on someone's list when their CoE changes in July.
- Their own material: the real MARN, ABN and professional indemnity certificate, real photographs of the office and the team, real reviews from the Google Business Profile feed, and the real phone number in place of the reserved
(08) 9000 0xxxpattern.
Iteration log
- Pass 1 — Craft. Measured every contrast pair from the shipped tokens rather than the spec (the figures in the palette section above are those measurements; approval green as small text came in at 4.64:1, confirming it stays a lines-and-marks colour and that the pre-minted
#116049ink does all the green typesetting). Then drove the whole planner and read the pixels. Five real defects fell out. (a) The "nationality & current visa" field'spatterncontained an escaped forward slash, which Chrome's v-flag regex engine rejects — the attribute threw atcheckValidityand the field silently stopped validating; the class is now letters, digits, spaces, commas, full stops and hyphens, and the placeholder changed from "Filipino · 482" to "Filipino, 482". (b) The masthead overflowed at 1200 px by 15 px — the wordmark tag now hides below 1341 px and the nav gap tightens with it. (c) The stamp card overlapped the fourth roundel and the "not stamped" caption at 1200; the whole sheet was recomposed around a reserved upper-right corner (see below). (d) Paper-grain dots spawned past the viewBox and read as horizontal-overflow offenders in the 375 and 560 probes even with a cleanscrollWidth; they now spawn inside a 20-unit inset. (e) Two harness bugs of my own — a truncated declaration assert and a reduced-motion expectation computed with the wrong child count — fixed in the harness, not in the page.
The screenshot review then caught what no assert could: the sheet was drawn in a 1080-unit box displayed at 660 px, so every stage label rendered at about 8.5 px; the paperclip sat on top of the sheet's own header; the figure marks read as pins rather than people; and the stamp card's service line wrapped to three lines in a 105 px column. The sheet was rebuilt in a780 × 520unit box (labels now ~11.8 px at 1200), the badge's grid was restructured so the service line spans the full card, the figure marks were redrawn with square shoulders under a rounded top, the paperclip moved to the top edge clear of both the header and the card, and the passport's internal type became scale-compensated. 470 assertions green. - Pass 2 — Depth. Added the dashed leader that ties the figure marks to the first roundel — the sheet now reads as one document rather than two illustrations sharing a page — and a second-read
FILE HM‑2026‑0371reference stamped faintly in the corner. Made the route's inking semantically exact: a segment is green only when we carry the file across it, so on a document review the handover arrow after stage one is dashed grey rather than a green arrow pointing into a stage we don't do. Split the subclass stamp into a two-line "SUBCLASS / 189 · 190 · 491" so it fits the passport page at every scale, and gave the badge's spec line two deliberate lines so a long visa name never orphans a word. On a partner visa the partner figure now draws in gold outline with a "(sponsor)" caption, which is the one place a control's disabled state is also a drawing decision. Re-drove every worked example, both lock sequences, the memory-invalidation sequence and two rapid-fire bursts. - Pass 3 — Hardening. Swept sixteen viewport widths from 375 to 1600, asserting at each one: no horizontal overflow, the wordmark's right edge against the call button's left edge and the call button against the Consult button, no drawn element intersecting the stamp card's box, and the card docked below 641 px and on-scene at or above it. All sixteen clean. The 375 layout was reviewed at native resolution: the phone sheet drops the wordmark line from its header (the masthead carries it two rows above) so the passport can sit clear of the figure marks, the badge docks beneath the sheet carrying only the short forms, and the stacked route's labels sit beside their roundels. Reduced motion verified — no rAF loops, the bloom parked at full rather than blank, identical frames 1.2 s apart, and every control still working. DPR 2 checked, and a desktop→phone→desktop resize confirmed to swap layouts, keep the total and leave exactly one loop running. The service-area map failed its own legibility test at 375 — labels landed under 8 px — so the label sizes went up and the map crops its
viewBoxto the drawn extent below 641 px; the suburb list beside it is the readable index either way. The map's Malaga pin also moved north-east and the office label shortened to "St Georges Tce office" so the two stopped grazing each other, the form's placeholder ink was given an explicit token at 5.02:1 rather than inheriting the browser's grey, the FAQ column was capped at 900 px, and the fees grid's last eyebrow shortened so its price aligns with the row. The Chanel rule removed the "the passport on the desk" caption. Final read of the copy in Australian English. Zero console errors on both pages, and this guide probed at 375 and 1200 for overflow, oneh1, the schema panel and the colophon. 488 assertions green in the final run.
Two things the concept left to composition were resolved here. The stamp card's anchor is a constraint, not a coordinate: the sheet reserves the box x ≥ 430, y ≤ 270 in scene units and nothing drawn is ever composed into it — every drawn element sits either left of x 285 or below y 356 — which is what makes "never over the drawn subject" survivable at 641 px, where the fixed-pixel card is 41 % of the sheet's drawn width. The concept's figure cap was the other one: its enumeration (you, your partner, up to four children) sums to six marks rather than the five the line labelled it, so the sheet draws six and the caption counts the file honestly. And the phone layout is a second composition rather than a crop — the proportional route is honest at any width, but below 641 px it stops being legible, so it stacks.
This is a demonstration build by Sapience Analytics. Want one pointed at your customers?