Cornerstone Framing

Generative Assets · Industry Demos XXVII · site 349

Cornerstone Picture Framing — how it was made

A conversion-first landing page for a fictional Fremantle custom picture framer, built as the pattern Sapience Analytics would ship for a real framing workshop: size the piece and pick the moulding, mat and glass on the page, see the price on a gallery wall label, then send the request.

Concept

Cornerstone Picture Framing is a two-framer workshop on Wray Avenue, Fremantle: custom framing, mat cutting, UV and museum glass, float mounting and object framing. The audience is the couple with a print from the markets, the family with a grandfather's medals, the artist framing twelve works for a group show, and the buyer who paid too much for a poster to hang it with clips. The page has one job: a framing request with the size, moulding, mat and glass already priced, so the first phone call is about the piece and the drop-off day, not "roughly how much".

Cornerstone Picture Framing is a fictional business — a picture framing industry demonstration designed & built by Sapience Analytics, part of the Generative Assets collection. The phone number uses the reserved (08) 9000 0349 pattern, the ABN is a placeholder, and the address stays at suburb level.

Palette — measured, not assumed

Argued from a gallery wall, charcoal mount card, museum-green baize and a gilt moulding. Every ratio below was measured from the shipped tokens with WCAG arithmetic in Pass 1; the spec's figures were hypotheses.

#ECEAE4 gallery greyPage ground — the wall the frame hangs on.
#26241F charcoalBody ink and the ledger ground. Measured 12.89:1 on gallery grey (spec ≈13).
#2F5D50 museum greenCTAs, links, chip selection. White labels 7.49:1 (spec ≈7); on the ground 6.23:1 (spec ≈6.5). No two-token remedy needed.
#24473D green deepHover fill and small green copy — 8.54:1 on the ground; white on it 10.28:1.
#C29A4A giltFrame highlights, rules, dimension leaders, chip hover, focus ring. Lines and marks only — 2.18:1 on the ground, never used for text.
#7C5C1E gilt inkEyebrows and the wall-label declaration line. Measured 5.12:1 on the ground (spec ≈6 — under the hypothesis, still AA at the ≥12.5px 700-weight sizes it is used at) and 6.16:1 on the white card.
#5C574D ink softSecondary copy — 5.97:1 on the ground, 7.18:1 on cards.
#D8B86A gilt lightGilt-coloured copy on the charcoal ledger and footer — 8.11:1 (the base gilt measures 5.92:1 there; the lighter variant is the on-dark remedy).

Type

Playfair Display (600, with an italic moment) — the serif on a gallery label — carries the wordmark, headings, the wall label's title and price, and the display line set huge above the frame: "SIXTY BY EIGHTY, OAK AND A SINGLE MAT", which re-sets from the steppers and chips (dimensions in words for pieces under a metre). Work Sans does the body, controls and ledger; the SVG dimension tags use it too so the scene and the page share one voice. Body is 17px on desktop and 16px in form fields, never under 16 on mobile.

The signature — the Frame Studio

A single SVG stage (a warm gallery wall under a drawn track light, with a hook and hanging cord) holds a drawn moulding, mat and artwork that resize to the width and height steppers. The artwork is a procedural landscape swatch — a nested <svg viewBox="0 0 200 200" preserveAspectRatio="xMidYMid slice"> with a sky gradient, a gilt sun and four layered hill paths in the palette — so any aspect ratio crops the same picture rather than stretching it. Geometry is computed in centimetres (artwork + float gap + mat border + moulding profile), scaled to fit a fixed frame box, and capped so a 20 × 20 cm piece reads honestly small while a 120 × 120 fills the wall; the dimension tags always print the true centimetres. Moulding chips swap the frame's fill (an oak gradient with a rotated grain pattern clipped to the band, matte ash, a gilt gradient with a heavier bevel highlight, chalk white) and its profile width (4.2 / 3.2 / 5.2 / 3.6 cm). Mat chips resize the border (6 cm single, 7 cm double with a thin gilt reveal); the float toggle opens a 2 cm gap around the artwork and paints a blurred drop shadow under it. Glass chips change the reflection: standard is a skewed white sheen band, UV adds a faint violet edge band, museum drops the sheen to 7% so the picture reads clearest.

Motion: state changes tween the displayed centimetres over 380 ms (900 ms on the first draw with a scale-in — the dual-speed redraw), and a token bumped in every handler before the state swap invalidates any in-flight tween so rapid-fire clicks can never index a stale frame. The gallery light drifts across the glass on a 9-second sinusoid whose range (0.22–0.78 of the glass width) never lets the sheen leave the pane — a never-invisible floor rather than phase arithmetic. The rAF loop clamps dt at zero and 50 ms, pauses on document.hidden, and under prefers-reduced-motion draws the settled frame once with the sheen parked mid-glass. The price is drawn as a gallery wall label beside the frame — an HTML overlay so the type stays crisp — that moves into the flow beneath the stage when the scene card is under 600px wide, and the stage itself switches to a tighter 480 × 430 viewBox with larger dimension tags under 480px.

Pricing model — pinned anchors, measured outputs

GST-inclusive. Foam-core backing, D-rings and cord are included and declared on the ledger, the wall label and the a11y mirror — never a line item. Moulding is priced per linear metre of the artwork's perimeter (2 × (w + h) / 100 — the mat border sits outside those numbers and is priced in the mat line, stated on-card); mat and glass by the artwork's area in two bands (≤ 0.5 m² / > 0.5 m²). On the ×10 cm grid, 2(w + h) is a multiple of 20, so the perimeter is a multiple of 0.2 lm and every rate × 0.2 is a whole dollar (12 / 10 / 17 / 9) — integer-safe by construction; the probe carries an integerSafe flag and the harness asserts it on every scenario. Totals display to the whole dollar.

LineRateNotes
Raw oak moulding$60 / lm4.2 cm profile drawn
Black ash moulding$50 / lm3.2 cm profile
Gilt moulding$85 / lm5.2 cm profile, bevel highlight
White moulding$45 / lm3.6 cm profile
Mat — none / single / double$0 · $35/$55 · $55/$85small band / large band
Glass — standard / UV / museum$30/$55 · $60/$110 · $120/$220small band / large band
Float mount+$40flat, live at every combination
Oversize (w or h ≥ 100 cm)note only"over a metre we glaze in acrylic — same price band"; badge, ledger, stepper card and mirror all carry it
Canvas stretching, block mounts, medals, jerseys, objectsno number"quoted on the piece" — grid and FAQ

Worked examples — all measured from the running page against an independent oracle

ScenarioArithmeticMeasuredNote
Rest: 60 × 80, raw oak, single mat, UV, no float2.8 lm × 60 = 168 + 35 + 60$263none
20 × 20, white, no mat, standard0.8 × 45 = 36 + 0 + 30$66grid floor
50 × 100, gilt, double, museum3.0 × 85 = 255 + 55 + 120 (0.50 m² — small band)$430oversize note present
60 × 90, gilt, double, museum3.0 × 85 = 255 + 85 + 220 (0.54 m² — large band)$560note absent — band flip asserted both ways
100 × 100, black ash, no mat, standard4.0 × 50 = 200 + 0 + 55$255oversize note
Rest + float263 + 40$303none
Rest, black ash2.8 × 50 = 140 + 35 + 60$235none
Rest, museum glass168 + 35 + 120$323none
120 × 120, gilt, double, museum, float4.8 × 85 = 408 + 85 + 220 + 40$753grid ceiling, oversize note
90 × 20 → 100 × 20, white, no mat, standard$129 → $138note absent → presentoversize boundary both sides
Grid floors20 × 20 white + single mat / UV / museum$35 · $60 · $120 linesservices "from" prices match

Fourteen further pseudo-random control vectors were driven against the oracle in the harness, plus a rapid-fire drive (ten clicks in one evaluate, then a second burst back to rest) — every total, band, note state and integer-safety flag matched. The rest-state figure measured from the running page is $263, exactly the spec's pinned figure; no spec correction was needed.

Conversion decisions

Local SEO we'd implement for the real business

The live page emits only WebPage, CreativeWork and a BreadcrumbList naming it a demonstration — fictional LocalBusiness data in a real index would be dishonest markup. For the real workshop we'd ship a Store record (the schema.org organization subtype for a retail workshop) with real hours, geo, price range and a reviews feed:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Store",
  "name": "Cornerstone Picture Framing",
  "image": "https://example.com.au/workshop.jpg",
  "url": "https://example.com.au/",
  "telephone": "+61 8 9000 0349",
  "priceRange": "$$",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "Wray Avenue",
    "addressLocality": "Fremantle",
    "addressRegion": "WA",
    "postalCode": "6160",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": -32.06, "longitude": 115.75 },
  "openingHoursSpecification": [
    { "@type": "OpeningHoursSpecification", "dayOfWeek": ["Tuesday","Wednesday","Thursday","Friday"], "opens": "09:00", "closes": "17:00" },
    { "@type": "OpeningHoursSpecification", "dayOfWeek": "Saturday", "opens": "09:00", "closes": "13:00" }
  ],
  "areaServed": ["Fremantle","South Fremantle","East Fremantle","Cottesloe","Melville"],
  "hasOfferCatalog": {
    "@type": "OfferCatalog",
    "name": "Framing services",
    "itemListElement": [
      { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Custom picture framing" }, "priceSpecification": { "@type": "PriceSpecification", "minPrice": 66, "priceCurrency": "AUD" } },
      { "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Museum glass glazing" }, "priceSpecification": { "@type": "PriceSpecification", "minPrice": 120, "priceCurrency": "AUD" } }
    ]
  },
  "aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "112" },
  "review": [
    {
      "@type": "Review",
      "author": { "@type": "Person", "name": "Real customer name" },
      "datePublished": "2026-05-14",
      "reviewRating": { "@type": "Rating", "ratingValue": "5" },
      "reviewBody": "Pulled from the Google Business Profile reviews feed — never typed by hand."
    }
  ]
}
</script>

Alongside it: a Google Business Profile with the workshop pinned on Wray Avenue and hours synced, service pages per line (custom framing, mat cutting, museum glass, float mounting, object framing) with the "from" prices as on-page text, suburb mentions that match the areas actually served, and review-request links printed on the collection docket.

What would change for the real client

Iteration log

Pass 1 — Craft

Pass 2 — Depth

Pass 3 — Hardening

Verified headless with puppeteer-core on port 8404: state probe window.__framing (scenario, lm, area band, per-line prices, total, note, badge text and mode, settled flag), screenshots at 375 / 1000 / 1200 inspected at native resolution.