FernbrookSchool of Music

Guide · Industry demonstration № 329

A term of music, priced on the stave

Fernbrook School of Music is a fictional Applecross tuition studio — piano, guitar, voice, drums and violin, terms of ten weekly lessons. The page has one job: turn a parent's "how much would lessons be for the two of them?" into an enrolment enquiry with instruments, lengths and the family total already settled. The signature is a Term Planner drawn as a grand stave — every enrolment becomes a note, and the family total sits on the end bar.

Palette

The practice room at golden hour

Every colour is argued from the room: the ivory of piano keys and afternoon light, ebony from the case, plum from the recital curtain, brass from the metronome and the stands. Spec-time contrast figures were treated as hypotheses (W32) and measured by WCAG arithmetic from the shipped tokens during Pass 1 — measured values below.

Studio ivory #F7F3EC

Page ground. Warm without being cream-and-terracotta; the light through the studio window at 5pm.

Ebony #201B24

Body ink and the notes themselves. Measured 15.27:1 on ivory (spec hypothesis ≈14:1 — passed with room).

Recital plum #5A3A6E

CTAs, links, the price badge. White labels on plum measured 9.27:1; plum text on ivory 8.38:1. No two-token remedy needed.

Brass #B8933F

Stave lines, metronome marks, rules — lines and marks only (2.61:1 on ivory, deliberately never used for copy).

Brass-ink #75601C

The pre-minted text twin for brass-coloured small copy: eyebrows, tempo markings, the family-discount note. Measured 5.51:1 on ivory (spec hypothesis ≈6:1 — under the guess, still comfortably past 4.5:1).

Ledger gold #D9BE7A

Minted during Pass 1 for the discount line on the dark ledger — brass-ink vanished on ebony, this measures 9.32:1 there.

Type

Fraunces & Nunito Sans

Fraunces (600, optical sizing on) carries the display voice — a warm serif with recital manners, used for the wordmark, headings, the huge "TERM ONE, TEN LESSONS", and italic for the family total and the tempo-marking notes under the stave. Nunito Sans is the workhorse: rounded enough to feel kind to parents, set at ≥16px body with weights 400/700/800 doing the hierarchy work. The one moment of typographic bravery is the planner's display pair — the uppercase Fraunces line swapping live with the enrolment count, the italic total beneath it like a marking on a score.

Signature

The Term Planner on a stave

The planner is a single inline SVG: a grand stave ruled in brass with a curly brace, an end bar, and a metronome beside it. Each enrolment renders as a drawn note on the stave with its instrument's silhouette above it — and the note value is honest musical notation for the lesson length: 30 minutes draws a quarter note, 45 a half note, 60 a whole note, and a group lesson draws a beamed pair of quavers (a shared lesson, literally). The term total sits in a plum badge on the stave's end bar — inside the signature's artwork and inside the first 750px at 1200 wide, because the thumbnail is the commercial argument (W30). The family-discount note renders under the stave in Fraunces italic, like a tempo marking.

Engineering the redraw

Honest pricing

The family-discount engine

Every figure is pinned per term (ten weekly lessons) and the planner's output was verified against an independently reimplemented oracle across all six binding worked examples, plus a rapid-fire race drive.

Pinned anchors — per term of 10 lessons
LinePriceAvailability
Private 30 min$420 ($42 a lesson)all five instruments
Private 45 min$580 — AMEB prep includedall five instruments
Private 60 min$740 — AMEB prep includedall five instruments
Group beginners$280 (max 4, 30 min)piano & guitar only; length locked to 30 min
Instrument hire+$60 per studentguitar & violin, any length/mode
Ensembles & theorytimetabled each term — no number by designask for this term's sheet

The discount rule, stated once and shipped everywhere

Two or more students: 10% off every enrolment's term tuition except the single most expensive. The note is a pinned template (W31) — "family discount — saves $X" where X = Σ 0.10 × (each tuition except one instance of the highest). Ties resolve by exactly one counting as highest (two group-piano enrolments at $280 each discount one of them: saves $28). Hire fees are never discounted — tuition only, stated on the ledger. 10% of every anchor {420, 580, 740, 280} is a whole dollar, so totals are integer-safe by construction.

The disable / lock matrix (W18/W31 — every cell pinned)

InstrumentGroup modeTake-home hire
Pianolive ($280)disabled — "the piano stays here — practice-room cards included"
Guitarlive ($280)live (+$60)
Voicedisabled — "taught one-on-one — voices and drum kits don't share well"disabled — "you already own the instrument"
Drumsdisabled — same on-page reasondisabled — "studio kit provided — your neighbours said thanks"
Violindisabled — same on-page reasonlive (+$60)

Selecting group forces the length to 30 minutes (the 45/60 chips disable with the lock note — 45/60 group combinations do not exist). Switching a group row to a one-on-one instrument falls the row back to private; switching a hired row to piano/voice/drums clears the hire. Every control either changes the price honestly or visibly says why it can't.

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

ScenarioArithmeticMeasured
Rest: 1 student, piano private 30420$420, no note
Piano 30 + guitar 451,000 − 42$958 · "saves $42"
Piano 30 + guitar 45 + drums 601,740 − (42 + 58)$1,640 · "saves $100"
Two group-piano enrolments (tie rule)560 − 28$532 · "saves $28"
Violin private 45 + hire, one student580 + 60$640, no discount
Violin 45 + hire, piano 60 (hire excluded)1,320 − 58 + 60$1,322 · "saves $58"

The cheapest plannable output — one group enrolment at $280 — equals the services grid's "group beginners $280 a term" line, and the privates floor $420 matches "from $420 a term ($42 a lesson)" (W12: the page never argues with itself).

Conversion decisions

Why the page is shaped like this

Local SEO

What we'd implement for the real business

This demo page ships only WebPage/WebSite/BreadcrumbList JSON-LD naming itself a demonstration — fictional structured data in a real index is dishonest markup. For a real school we would ship the schema below. schema.org has no MusicSchool subtype, so the honest choice is School (the EducationalOrganization family) with the offer catalogue carrying the tuition lines:

{
  "@context": "https://schema.org",
  "@type": "School",
  "name": "Fernbrook School of Music",
  "description": "Private and group music tuition — piano, guitar, voice,
    drums and violin — terms of ten weekly lessons in Applecross, Perth.",
  "url": "https://fernbrookmusic.com.au",
  "telephone": "+61 8 XXXX XXXX",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "(real street address)",
    "addressLocality": "Applecross",
    "addressRegion": "WA",
    "postalCode": "6153",
    "addressCountry": "AU"
  },
  "geo": { "@type": "GeoCoordinates", "latitude": -32.016, "longitude": 115.836 },
  "openingHoursSpecification": [
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
      "opens": "12:00", "closes": "20:00" },
    { "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Saturday", "opens": "09:00", "closes": "13:00" }
  ],
  "areaServed": ["Applecross","Ardross","Mount Pleasant","Booragoon",
    "Como","South Perth","Willetton"],
  "makesOffer": [
    { "@type": "Offer", "name": "Private lessons — 30 min, term of 10",
      "price": "420", "priceCurrency": "AUD" },
    { "@type": "Offer", "name": "Group beginners — 30 min, max 4",
      "price": "280", "priceCurrency": "AUD" }
  ],
  "aggregateRating": { "@type": "AggregateRating",
    "ratingValue": "4.9", "reviewCount": "87" },
  "review": [
    { "@type": "Review",
      "author": { "@type": "Person", "name": "(real student's parent)" },
      "reviewRating": { "@type": "Rating", "ratingValue": "5" },
      "reviewBody": "(their real words, with permission)" }
  ]
}

Plus: a Google Business Profile wired to the same NAP, term-dates content refreshed each school term (search spikes in weeks 8–10 and the January rush), and suburb-level landing content for the riverside catchment.

What changes for the real client

Their photos of the studio and recitals replace the drawn scenes; their reviews feed (Google) replaces demo copy; the enquiry form posts to their booking stack — for music schools that's My Music Staff for scheduling/billing, Square for term payments, and Xero for the books. The planner keeps working exactly as shipped: it's front-end arithmetic on their real price list.

Process

Three passes, logged honestly

Pass 1 — Craft

  • Measured every spec contrast hypothesis by WCAG arithmetic: ebony 15.27:1, white-on-plum 9.27:1, plum 8.38:1, brass-ink 5.51:1 (under the spec's ≈6:1 guess but comfortably compliant). Brass held at lines/marks only.
  • The discount line on the dark ledger was first set in brass-ink (5.5:1 on ivory, ~2.8:1 on ebony) — minted ledger-gold #D9BE7A (9.32:1 on ebony) for it and the stave-note family.
  • Removed a dead duplicated ledger loop left from drafting; the 375 screenshot showed anchor jumps tucking section headings under the sticky masthead — added scroll-margin-top to every section.
  • Drove the full worked-example set with the complete control vector pinned per scenario — all six matched the oracle to the dollar on first run.

Pass 2 — Depth

  • Second-read detail: the note values are honest notation — 30 min draws a quarter note, 45 a half, 60 a whole, group a beamed quaver pair. Nobody needs to notice; musicians will.
  • Refined the redraw stagger (first draw 260+230i ms, subsequent 40+70i ms) and the glyph ease to a single crafted cubic-bezier(.22,.7,.2,1) shared with the buttons.
  • Gave each enrolment row its own stave pitch so a three-student family reads as a rising phrase, and the metronome's beat dot pulses in time with the pendulum (2× swing frequency, floor 0.55).
  • Micro-interaction: the price badge pulses (a 450 ms scale pop, CSS transform on a group carrying no transform attribute) whenever the total actually changes — silent on first draw and under reduced motion.
  • Exercised every disable/lock cell: group on voice/drums/violin (reason shown), the 30-min lock under group, all three hire refusals, and the fall-backs when an instrument switch invalidates mode or hire.

Pass 3 — Hardening

  • 375px masthead first (W18): wordmark right edge vs call/enrol cluster measured with clear air; phone number collapses to icon+label under 560px so nothing wraps.
  • Empty submit: panel stays hidden, ≥4 :invalid signals; filled submit: panel appears with the "received / we'd call" copy. Rapid-fire drive (five clicks, one evaluate, no settle) left state, figures and settled flag coherent.
  • Reduced-motion path renders the settled frame (pendulum parked, glyphs opaque, dash-draw complete); rAF pauses on document.hidden; delta clamped at zero and capped.
  • Chanel rule: cut the service-area map's second ghost coastline stroke — one drawn coast reads cleaner and nothing else on the map is doubled.
  • Guide tables wrapped in .table-scroll at build time (W21); both pages screenshot-reviewed at 375 and 1200×750.