Generative Assets · Industry Demos · how it was made
How the South Mole Seafood demo was built
South Mole Seafood is a fictional Fremantle fish market and wholesale counter beside the Fishing Boat Harbour — Abrolhos snapper and scallops, Shark Bay whiting, Exmouth prawns and western rock lobster, over the counter seven days and out to restaurant kitchens by six each morning. The page exists for one reader: the chef ordering six kilos of snapper fillets for Friday. Its single job is an order request with the species, the cut, the weight and the delivery already priced — honestly, to the whole dollar, with the restaurant rate applied where it's earned.
The Catch Board
The signature element is a drawn SVG display case seen head-on: a bed of crushed ice hatched in harbour teal over white, a stainless rail across the front, a case card clipped to the rail, the packing for your chosen delivery on the bench, and a folded paper price ticket above the ice. Every control redraws the case honestly and reprices the order from the pinned anchors:
- Species chip redraws what is on the ice: pink snapper and Shark Bay whiting as parametric side-view fish (body, dorsal and anal fins, pectoral, gill plate, lateral line, eye), Exmouth prawns as segmented shells swept along a circular arc with rostrum, antennae and legs, Abrolhos scallops as fluted fan shells with the meat and roe, and western rock lobster as carapace, five tapering tail segments, tail fan and two long antennae.
- Prep chip redraws the cut of that species and re-rates it: whole, gutted (a belly slit with the cavity drawn), or filleted (a wedge shape with the myotome flakes, the blood line and — on snapper — a silvered skin band clipped to the back edge only). Prawns go green shell-on, cooked, or peeled (a smooth arc with the vein and no head); scallops in the half shell, roe on, or roe off; lobster whole raw, cooked, or halved with the tail meat lifted clear.
- Weight stepper 1–15 kg lays out more of it — one drawn unit per kilo, where a unit is the honest trade quantity: one fish, two fillets, three prawns, five scallops, one lobster. The drawn cap is eight units; beyond 8 kg the ice draws eight and a stack of foam trays appears behind them with the true count printed on the front ("12 kg"), and the catch shifts right to clear the trays.
- Delivery chip changes the packing on the bench: paper and twine for counter pickup, an insulated lidded box for the metro van, a strapped foam carton for the overnight regional freight.
- The price badge is drawn as a folded paper price ticket — white card, slate edge, a folded corner and a teal rule under the figure. Two lines always: the total and the provenance line for that species ("Abrolhos, off the boat this week"). The restaurant-rate note appears beneath it from five kilos, and the availability declaration sits under a dashed rule at the foot, always.
- A slow loop keeps the case alive: meltwater beads under the rail, swells, falls and rings the drain gutter on a 2.6 s cycle, while an ice glint travels the bed on a 9.2 s cycle with its opacity never dropping below 0.55 — a never-invisible floor (W18), so the signature reads at any capture instant rather than being phase-tuned to the seven-second settle.
- Two second-read details: a stainless counter scale hangs on the wall and its needle actually reads the order's weight (one full revolution across the 15 kg range), and a restaurant-rate stamp lands on the case card the moment the weight earns it.
Pinned anchors (GST inclusive, per kilo, whole kilos)
| Species | Prep A | Prep B | Prep C |
|---|---|---|---|
| Pink snapper | whole $28 | scaled & gutted $32 | fillets, skin on $52 |
| Shark Bay whiting | whole $34 | scaled & gutted $38 | fillets, skinless $58 |
| Exmouth prawns | green, shell on $45 | cooked $48 | peeled green $68 |
| Abrolhos scallops | in the half shell $58 | roe-on meat $72 | roe-off meat $84 |
| Western rock lobster | whole raw $95 | whole cooked $105 | halved & cleaned $115 |
| Rule | Anchor | What it multiplies / tests against |
|---|---|---|
| Restaurant rate | −$4 a kilo from 5 kg | changes the rate, never the billed weight; the rate multiplies the actual kilos. Boundary exactly reachable — the stepper is whole kilos. |
| Counter pickup | $0 | no minimum |
| Metro delivery | $25, free from $240 | flat, and outside the fish subtotal. The $240 threshold tests the fish subtotal only. Reachable exactly: 5 kg snapper fillets at the trade rate = 5 × 48 = $240. |
| Metro minimum | $120 of fish | tested against the fish subtotal only, never fish + delivery. Reachable exactly: 5 kg whole snapper at the trade rate = 5 × 24 = $120. |
| Regional freight | no number | "quoted by the run" — the badge prints $<fish subtotal> + freight quoted (the W40 partially-computable form), never a bare "quoted". No minimum. No short form — the full string at every width. |
| Availability declaration | no number | price-less and always present, on the ticket, the ledger and the a11y mirror — and in the confirmation panel. Short form at ≤640 px: "we call before we substitute". |
Every rate is a whole dollar and the weight grid is whole kilos, so no total ever needs rounding — the harness asserts every total is an integer across the whole reachable surface. There is no empty state: a species chip, a prep chip and a delivery chip are always selected, and the weight floors at 1 kg.
The delivery force, and what happens on the way back
Metro delivery starts at a $120 fish subtotal. While metro is selected, any change that drops the fish subtotal under $120 forces the order to counter pickup, remembers metro, and disables the metro chip with the reason printed on the page. Raising the subtotal back to $120 or more restores metro. Three semantics matter and all three are shipped and asserted:
- Invalidation (W41): an explicit delivery-chip change while forced clears the memory. Drive: 6 kg fillets on metro → 2 kg (forced off, metro remembered) → click regional freight (memory cleared) → back to 6 kg → the order stays on regional freight and the badge reads "$288 + freight quoted".
- Partial unwind (W42): if the constraint relaxes but the remembered value is still invalid, the forced value holds. Drive: 5 kg whole snapper on metro → 1 kg (forced) → 2 kg ($56, still under $120) → stays on counter pickup with metro still remembered → 5 kg → metro restored.
- The reason is never silent. Under $120 the chip is disabled and the page says "metro delivery starts at $120 — this order is $112, so we've put it on counter pickup and we'll switch it back the moment the fish reaches $120."
Worked examples measured from the running page
| Scenario | Arithmetic | Total | Note · line 2 |
|---|---|---|---|
| Rest — pink snapper, fillets skin on, 6 kg, metro | rate 52 − 4 = 48; 6 × 48 = 288 ≥ 240 → delivery $0 | $288 | "restaurant rate — $4 a kilo off, $24 off this order" · "Abrolhos, off the boat this week" |
| Cheapest output — snapper, whole, 1 kg, pickup | 1 × 28 | $28 | = the services grid floor "$28 a kilo whole" |
| 5 kg whole snapper, metro (minimum met exactly) | 5 × 24 = 120 + 25 | $145 | "$20 off this order" |
| 4 kg whole snapper, metro | 4 × 28 = 112 < 120 → forced to pickup | $112 | note absent · metro disabled |
| …then step back to 5 kg | metro restored, 120 + 25 | $145 | note present |
| 5 kg snapper fillets, metro (free-delivery boundary) | 5 × 48 = 240 → delivery free | $240 | "$20 off this order" |
| 4 kg snapper fillets, metro | 4 × 52 = 208 + 25 | $233 | note absent |
| 8 kg peeled green prawns, pickup | 8 × 64 | $512 | "$32 off this order" · eight units drawn, no tray |
| 2 kg lobster halved & cleaned, metro | 2 × 115 = 230 + 25 | $255 | note absent · "Fremantle boats, weather permitting" |
| 10 kg whiting fillets, metro | 10 × 54 = 540 → delivery free | $540 | eight units drawn, tray reads "10 kg" |
| 3 kg roe-on scallops, metro | 3 × 72 = 216 + 25 | $241 | note absent |
| 15 kg whole raw lobster, pickup | 15 × 91 | $1,365 | tray reads "15 kg" |
| Regional freight, 6 kg snapper fillets | 288, freight not priced | $288 + freight quoted | the W40 partially-computable badge form |
| Rapid-fire — pickup, prep whole, 5 kg, then lobster → prawns → scallops → whiting in one evaluate | 5 × 30 | $150 | "$20 off this order" · loop count settles back to exactly 1 |
Every figure above, both boundary pairs, all six grid floors and 45 further control vectors across the whole reachable surface were checked against an oracle re-implemented from the anchors inside the verification harness — never by importing the page's own code. Each scenario drive sets the full control vector explicitly (species, prep, weight, delivery) rather than inheriting load state (W33).
Palette — crushed ice, wet slate, harbour water, and the flesh of a snapper fillet
A pale ice ground, wet-slate ink, harbour teal doing all the marking, and a salmon flesh tone that lives only inside the drawn catch. Cold, clean and market-honest — chalk-board discipline without the chalkboard. It is held off the near-black + acid-accent default by the slate-not-black ink, and off cream + terracotta entirely by the cold ground. Every ratio below was computed with WCAG arithmetic from the shipped tokens during Pass 1, role, hex and ratio read from the same script row.
Pass 1 measurement reproduced every spec figure exactly — 13.27 / 14.99 / 16.96 / 5.97 / 7.92 / 5.29 / 7.54 / 8.51 / 2.77 / 5.52 / 6.24 all held to two decimals, so no token was re-minted. The two colours the measurement decided: the mark ink on the drawn catch is slate on the salmon, pale and shell fills (4.79 / 12.60 / 11.62:1) but flips to white on the cooked-prawn and both lobster fills, where slate would measure 3.12:1 and be swallowed (W42) — white on cooked reads 4.80:1 and on raw lobster 8.57:1. And the regional-freight labels on the map are salmon-ink on white land, never over water.
Type
The display moment is the rest-state line set above the case — "$288 · PINK SNAPPER · FILLETS · 6 KG" — rebuilt from state on every change, so the figure is always the live total and the species and cut are always the live selection. The price leads in salmon-ink; the middle dots travel with the token that follows them so a wrap never strands a dot at a line end. In the quoted state the same line reads "$288 + freight quoted · PINK SNAPPER · FILLETS · 6 KG".
Techniques
- Procedural SVG, no libraries. The backdrop (tiled wall, fluorescent tube and its pool of light, the hanging counter scale, the steel case lip, the ice bed with 150 deterministically-seeded crushed-ice facets under a teal hatch, the rail, the bench and its drain gutter) is drawn once per breakpoint from a small LCG so the ice is identical on every load. The catch, the trays, the case card, the packing, the scale needle and the effects live in a dynamic group rebuilt on every state change.
- Parametric catch geometry. Each species is a function of length and depth rather than a fixed path, so the same code draws a deep-bodied snapper and a slim whiting; prawn segments are annulus slices swept along a circular arc; the fillet's skin band and blood line are clipped to the fillet outline via
clipPathso nothing bleeds past the edge, and the outline is re-stroked over the clipped fill so the silhouette stays crisp. - Dual-speed redraw (W21). First paint staggers each drawn part at 26 ms with a 1.2 s cap; every later state change redraws at 10 ms per part with a 480 ms cap via a
firstDrawflag, so a chip tap reads as snap, not lag. Parts animate opacity only — never a property the same element also sets as an SVG presentation attribute (W16/W17). - Token-invalidated loop (W25). The meltwater and glint run in one
requestAnimationFrameloop whose token is bumped inside every control handler before the state swap; the stale loop exits on its next frame and the rebuilt scene starts a fresh one, so the probe'sloopscount settles back to exactly one — asserted after two rapid-fire bursts of six clicks each with no settle between. Delta time is clamped at zero and capped at 50 ms (W29), and the loop idles while the tab is hidden. - Ticket placement. The ticket is an HTML element right-aligned inside the scene at ≥641 px, positioned from the rendered SVG scale and re-placed on resize and after
document.fonts.ready. At ≤640 px it docks directly beneath the case as a two-column strip, still inside the Catch Board card, and the scene crops to a56 300 968 520viewBox that drops the wall and enlarges the case. Between 641 and 900 px an explicit mid-width variant tightens the ticket's setting — the strings stay full at every width above the dock; only the type scale changes. - Reduced motion. A CSS media query plus a
matchMediacheck: no loop starts, the meltwater is parked mid-fall with the bead on the rail, the glint is parked mid-travel, entrance transitions and the hero rise are disabled, and the ticket's settle transition is off. Every control still works. - State probe.
window.__fishmongercarries the species, prep, weight and delivery, the forced flag and the delivery memory, the list and trade rates, the fish subtotal, the fee, the total, the quoted flag, the badge string, both note forms, both provenance forms, both declaration forms, the drawn count and tray count, the disabled list,loops, and asettledflag set after the redraw cap — QA gates on state, never on seconds.
Conversion decisions
- Above the fold at 375 px: the business name, "Fremantle fish market and restaurant supply — off the boats, onto the ice, delivered across the metro", the Order the catch + Call (08) 9000 0372 pair, and the "On the harbour since 1994" trust line — all above the sticky bar at 375 × 667, measured. The lede drops its middle clause on phones so the trust line makes the fold.
- Order vs call: a fish order is a conversation about what landed, so the phone is never more than a tap away — a
tel:link in the masthead, a ghost button beside the primary CTA, one on the Catch Board, one in the footer, and a sticky Call the counter / Order the catch bar on phones. - The Catch Board feeds the form. Species, cut, weight, rate, delivery, the total, the trade note and the provenance line pre-fill the order textarea; "Send this order through" refreshes it and focuses the name field. The form fields are what a fish counter actually needs: name, phone, business or household (which counter takes it), suburb (where the box goes), the day it's needed, and the pre-filled order.
- Honest floors. The services grid's "from" prices are the Catch Board's cheapest outputs per species — $28 / $34 / $45 / $58 / $95 a kilo — and the delivery card carries the same $25 / free at $240 / $120 minimum the calculator applies. The trade note, the availability declaration and the disabled-metro reason all appear wherever the total does.
- Local confirmation, no fake network. An empty submit flags the required fields inline and keeps the confirmation panel hidden; a valid submit shows the designed panel naming the customer, the suburb and the order, repeating the availability declaration, and marked plainly as a demonstration. Nothing is ever posted anywhere.
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 market must not mark itself up as a real one. For the real client we would ship the block below. schema.org has no fishmonger or seafood-market subtype, and FoodEstablishment is for eating on the premises, so the top-level type is Store — an actual organisation subtype — with the specialty named through additionalType and the counter priced through hasOfferCatalog. Real reviews would be pulled from the Google Business Profile feed and marked up only with the reviewer's consent.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Store",
"additionalType": "https://en.wikipedia.org/wiki/Fishmonger",
"name": "South Mole Seafood",
"description": "Fremantle fish market and restaurant supply — Abrolhos snapper and scallops, Shark Bay whiting, Exmouth prawns and western rock lobster, filleted to order.",
"url": "https://www.example-southmole.com.au/",
"telephone": "+61 8 9000 0372",
"image": "https://www.example-southmole.com.au/counter.jpg",
"priceRange": "$$",
"currenciesAccepted": "AUD",
"address": {
"@type": "PostalAddress",
"addressLocality": "Fremantle",
"addressRegion": "WA",
"postalCode": "6160",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -32.06, "longitude": 115.74 },
"areaServed": ["North Fremantle", "Cottesloe", "Claremont", "Subiaco", "Perth", "Leederville", "Victoria Park", "Applecross"],
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"], "opens": "06:00", "closes": "17:00" },
{ "@type": "OpeningHoursSpecification", "dayOfWeek": ["Saturday","Sunday"], "opens": "07:00", "closes": "16:00" }
],
"knowsAbout": ["pink snapper", "Shark Bay whiting", "Exmouth prawns", "Abrolhos scallops", "western rock lobster", "wholesale seafood", "filleting to order"],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Off the boats",
"itemListElement": [
{ "@type": "Offer", "itemOffered": { "@type": "Product", "name": "Pink snapper, whole" }, "priceSpecification": { "@type": "UnitPriceSpecification", "price": "28", "priceCurrency": "AUD", "unitCode": "KGM" } },
{ "@type": "Offer", "itemOffered": { "@type": "Product", "name": "Pink snapper fillets, skin on" }, "priceSpecification": { "@type": "UnitPriceSpecification", "price": "52", "priceCurrency": "AUD", "unitCode": "KGM" } },
{ "@type": "Offer", "itemOffered": { "@type": "Product", "name": "Western rock lobster, whole raw" }, "priceSpecification": { "@type": "UnitPriceSpecification", "price": "95", "priceCurrency": "AUD", "unitCode": "KGM" } }
]
},
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.8", "reviewCount": "212" },
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "Real customer, 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 pinned to the Fishing Boat Harbour with the counter hours and the daily catch posted as updates, "fish market Fremantle" / "fresh seafood Perth delivery" / "wholesale seafood restaurant Perth" as the core phrases with the delivery suburbs as secondary, NAP consistency across the hospitality-supplier directories, and a reviews feed that updates without anyone touching the page.
What changes for the real client
- Standing restaurant orders: Ordermentum or Foodbomb for the wholesale side — the Catch Board's order becomes a real order line against a chef's standing weekly template, not a textarea, and the credit terms and the delivery run live where the driver can see them.
- The counter: Square or Lightspeed on the retail till, with the day's species and rates driven from the POS so the board and the counter can never disagree.
- Scale-to-invoice: a weigh feed from the bench scales, so the invoiced weight is the weighed weight — the single most common source of argument in seafood wholesale, and the reason the drawn scale on this page reads the order's weight.
- Xero for invoicing and the trade accounts, mapped line-for-line from the order.
- The market's own photographs of the case and the boats, a live Google reviews feed, the real ABN and food business registration, the real phone number in place of the reserved pattern, and a daily "what landed" post that drives the species chips from real stock rather than a fixed list.
Iteration log
- Pass 1 — Craft. Contrast measured from the shipped tokens: every spec figure reproduced exactly, so no token moved (see the palette note above). Three real defects, all found by driving and looking rather than by asserts. (a) 375 px overflowed to a 972 px scroll width — two causes: the ledger's availability declaration is a single span, so the
li span:last-child { white-space: nowrap }rule meant the whole 896 px sentence could not wrap, and the single-column hero track was1frrather thanminmax(0,1fr), so the scene SVG's intrinsic 1080 px width drove the track. Fixed with an explicit wrap rule on the declaration line and a clamped track plusmin-width:0on the card, holder, controls and ledger; scroll width back to 375 with zero non-SVG offenders. (b) The fillets read as blobs — the shape was too round and the skin band was stroked over the whole silhouette. Redrawn as a proper wedge (blunt shoulder, tail point) with the skin band and blood line clipped to the outline and the outline re-stroked on top, enlarged 128→150 units, and the pair laid parallel rather than crossed. (c) The ice hatch and facets were nearly invisible at render scale (0.16 opacity) — lifted to 0.28 with tighter spacing, and the case card grew from 334→430 units with its type from 16/13 to 23/18 so it is legible at scene scale. - Pass 2 — Depth. A mechanical label-collision sweep (ticket rect against every drawn group's bounding box at 641 / 800 / 900 / 1000 / 1100 / 1200 / 1440 px, at both 6 kg and 12 kg) found a real collision at 641 px: the ticket's fixed pixel height is a much larger share of a 555 px-wide scene, so its foot landed on the back row. Fixed with an explicit 641–900 px mid-width ticket variant (tighter type and padding, full strings kept per the wave pin) plus 14 units more headroom on the back row — zero intersections at every width now, minimum clearance 19 px at the tightest. Two second-read details earned their place: the wall's hanging counter scale now has a needle that reads the order's weight (one revolution across the 15 kg range), and a restaurant-rate stamp lands on the case card the moment the weight crosses five kilos — which meant dropping the duplicated weight from the case card's second line so the stamp had somewhere to sit without striking through it. The ticket also gained its settle transition, applied only after boot so it never animates in from the corner on first paint. Pass 2 drove all thirteen worked examples, both boundary pairs, the force, the restore, the memory-invalidation chain and the partial unwind by clicking the real controls.
- Pass 3 — Hardening. 375 px: masthead measured explicitly — the wordmark's right edge is 218 px against the call button's left edge at 239 px, and the Order button ends at 361 px inside the 375 px viewport, so no collision; the backdrop is now drawn only to the live viewBox so nothing is painted outside the mobile crop; scroll width 375 with zero non-SVG offenders. The ticket docks beneath the case at 640 and sits on-scene at 641, asserted both ways, with the short note, provenance and declaration forms at ≤640 and the full forms at 641 / 1000 / 1200 — the ledger and the a11y mirror always carry the full strings. Reduced motion verified: no loop starts, the bead sits on the rail with the droplet parked mid-fall, the glint is parked mid-travel, two frames 1.3 s apart are identical, and every control still reprices. Form
patternattributes compiled clean under Chrome's v-flag regexes (every literal(,),+and-escaped), which the zero-console assert is what surfaces. Focus rings on every chip, stepper, field, summary and link; tap targets ≥44 px; the sticky bar is solid white with nobackdrop-filteranywhere on the conversion chrome (W28). DPR 1, 2 and 3 and a live resize across the 640/641 breakpoint all re-place the ticket and re-crop the scene without a console error. Native-resolution screenshots at 375 / 1000 / 1200 reviewed by eye with an explicit label-collision sweep over the tray count, the species card and the ticket. The Chanel rule removed the wall's vertical tile grout — the horizontals carry the tiling on their own, and the verticals only added noise behind the hanging scale and the ticket. The restaurant-rate stamp and the meltwater drip both moved along the rail (to 500 and 640 scene units) after a 375 px screenshot showed the stamp clipping the case card's rate line and the drip landing where the stamp had gone.
Spec notes and decisions the concept left to the builder: the drawn unit is one kilo, and the cluster inside it is the honest trade quantity (one fish, two fillets, three prawns, five scallops, one lobster) — the drawn cap of eight units and the tray's printed count are the pinned honesty mechanism above 8 kg. The prep chip is an index (A/B/C) preserved across a species swap, since every species has exactly three preps that map one-to-one; the label, the rate and the drawing change with the species, the position does not. The regional-freight badge suffix has no pinned short form, so it carries the full string at every width, as the wave allows. Nothing in the concept was found arithmetically wrong: all thirteen worked figures, both boundary pairs and all six grid floors reproduced exactly against an independent oracle. Final harness totals: 443 asserts, all green — 302 in the behaviour harness (rest state, thirteen worked examples against the oracle, both boundary pairs, the force/restore/invalidate/unwind chain, every chip and stepper, two rapid-fire bursts, a 45-vector oracle sweep, the three-surface note and declaration checks with their absence cases, and the empty-then-filled form path) and 141 in the hardening harness (375 px layout and masthead, the 640/641 dock with short-versus-full forms on all three surfaces, reduced motion, focus rings, v-flag patterns, DPR 1/2/3, a live resize across the breakpoint, and the guide page's own structure and figures). Zero console errors or warnings at 375 / 640 / 641 / 1000 / 1200 and under reduced motion.
This is a demonstration build by Sapience Analytics. Want one pointed at your customers?