Generative Assets · Industry demo 276 · Shopfitting

How Millform Shopfitting was made

Design and build notes for a demonstration landing page: a fictional Osborne Park commercial shopfitter, a live-fitting SVG tenancy, and pricing that shows its working. Every pixel is procedural — no photographs anywhere on the page.

The concept

Millform Shopfitting is a fictional commercial fitout builder for café operators, retail tenants and allied-health owners across the Perth metro. The page has one job — book a site walk-through — and one argument: a fitout is a building built indoors in six weeks, so the firm that runs the program (landlord approval, trades in sequence, certifier and health signoffs) is the firm you want holding the keys deadline. Everything on the page, from the m² maths to the make-good line, performs that competence.

Palette — ply and blueprint

Argued from the workshop at 8am: sanded birch sheet under skylight, steel-blue shadow, setout lines on a taped plan, one timber-oil tin.

#EFE8DA · birch plyGround — the sanded sheet. A faint 96px vertical grain repeats across it.
#1C2733 · carcass inkStructure and primary type — the daylit workshop's steel-blue shadow.
#2D5FA8 · blueprintLine/mark accent — dimension lines, scope rules, CTA. 5.2:1 on ply, so it may carry short bold labels, never body copy.
#C25E2A · tag orangeThe site-tag on tested leads — chip-scale only: focus rings, active states, the tags in the scene.
#8F4218 · tag-inkDerived darker orange (5.9:1 on ply) for links and any orange TEXT duty — the W2/W5 ink/line split.
#46545F · soft inkDerived secondary body ink, 6.4:1 on ply — captions and support copy.

Type

The signature — the Fitout Scoper

Three venue chips, a 40–300 m² stepper and three spec chips drive a procedural SVG cutaway of the tenancy that fits out live. The scene is built as markup strings per element (stud walls, counter, joinery runs, exhaust hood, ceiling grid, duct, pendants), each wrapped in an outer <g transform> for position and an inner <g class="ein"> for the CSS entrance — position by attribute and animation by stylesheet stay on separate nested groups (the W16/W17 rule). The floor area stretches the drawn tenancy between 372 and 584 viewBox units with a blueprint dimension line pencilling the live m² beneath; spec chips add layers (refresh: paint, counter, pendants; mid: partitions, joinery, floor finish; full: ceiling grid, services duct, extra joinery). The rest state holds the tenancy about two-thirds fitted — the trailing third of the build sequence renders as work-in-progress at 0.62 opacity (dashed pendants, unfinished banquette), comfortably above the 0.4 visibility floor at any capture instant. Completed elements carry a small orange site-tag; offcuts sit swept into the slab corner — the second-read details. Redraws are dual-speed: the first render staggers 90 ms per element (capped ~1.1 s), every subsequent chip or stepper change staggers 34 ms capped at 360 ms plus a 300 ms fade, and a window.__shopfitter.settled flag flips when the redraw lands so QA gates on state, never seconds.

The pricing model — anchors and shape

Rates are flat $/m² per venue × spec, all-in (supplied, built and certified, trade-managed). The scoper's output is area × rate — deliberately linear, shipped as a documented pricing statement: at demo scale, the honest story is that the rate carries the compliance load of the venue class, not that price curves with area. Site-time bands are pinned per spec, not computed.

VenueRefresh $/m²Mid-spec $/m²Full custom $/m²Smallest honest job (40 m² refresh)
Retail$450$950$1,500$18,000 — the page floor
Café & hospitality$700$1,600$2,400$28,000
Office & consult$500$1,050$1,650$20,000

Conversion decisions

Local SEO we'd implement for the real business

This demo page ships only WebPage schema naming it a demonstration — fictional LocalBusiness/Review data in a real index is dishonest markup. For a real client the page would carry:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "@id": "https://millformshopfitting.com.au/#business",
  "name": "Millform Shopfitting",
  "description": "Commercial fitouts for cafés, retail and consult suites across Perth.",
  "telephone": "+61-8-XXXX-XXXX",
  "address": { "@type": "PostalAddress", "addressLocality": "Osborne Park",
               "addressRegion": "WA", "addressCountry": "AU" },
  "geo": { "@type": "GeoCoordinates", "latitude": -31.9016, "longitude": 115.8106 },
  "areaServed": "Perth metropolitan area",
  "openingHoursSpecification": [{ "@type": "OpeningHoursSpecification",
    "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
    "opens": "07:00", "closes": "16:00" }],
  "priceRange": "$$$",
  "aggregateRating": { "@type": "AggregateRating",
    "ratingValue": "4.9", "reviewCount": "87" },
  "review": [{ "@type": "Review",
    "author": { "@type": "Person", "name": "Real Customer" },
    "reviewRating": { "@type": "Rating", "ratingValue": "5" },
    "reviewBody": "Fitted out nine days before the rent-free ran out." }]
}
</script>

— fed by a live review pipeline, never hand-typed. Plus suburb-level service pages, GBP with fitout-category photos, and case-study pages per venue class (café / retail / consult) matching the query families tenants actually search.

What would change for the real client

Iteration log

Pass 1 — Craft

Headless harness (puppeteer, port 7001): 28 asserts, all green first run — one h1, canonical, WebPage-only schema, rest state café/120/mid displaying $192,000 against the independent oracle, full-custom crossing $288,000, floor scenario $18,000 equal to the services grid floor with the minimum-job note showing, empty submit on a fresh load raising 6 invalid fields + aria-invalid, filled submit confirming in the "we'd call" lexical family, sticky bar fixed with a tel: link at 375px, masthead collision-free (wordmark right edge 95px vs tel left 225px). The screenshot review then caught two things no assert saw: the café pendant run collided with the exhaust hood at the kitchen end, and the scene's "MID-MAKE" annotation was set in raw tag orange at ~3.4:1. Fixed both — pendants confine to front-of-house for café mid/full, annotation demoted to tag-ink.

Pass 2 — Depth

Added the second-read layer: offcuts swept into the slab corner, orange site-tags on completed elements (work-in-progress elements get blueprint dashes and 0.62 opacity instead), and a 500 ms price-tick colour pulse when the figure changes. Drove all nine venue × spec combos against the reimplemented oracle — nine matches; stepper ceiling 300 m² disables the up control; keyboard drive of chips and FAQ passed; reduced-motion emulation renders the scene settled and complete with no entrance. One harness bug caught (the combo loop left spec at full custom, so the 300 m² assert expected the wrong rate — the displayed $720,000 was the page being right); fixed the harness, not the site.

Pass 3 — Hardening

375px masthead screenshot reviewed first — clean single row, wordmark and phone clear of each other. Chanel cut: removed the scene's duplicate "TENANCY SECTION" header line (two stacked mono annotations was one too many). Guide page probed at 375px with the pricing table in a scroll wrapper; reserved-phone positive sweep confirms every (08) 9xxx number on both pages uses the 9000 exchange; resource allowlist scan clean (Google Fonts only); the scoper's bounding box intersects the first 750px at 1200 wide for the thumbnail; final copy read killed two flabby phrases. Zero console errors across every run.

Techniques