Boxline Self Storage — how this page was made
A conversion-first landing page for a fictional Bibra Lake self storage facility. The audience is a household mid-move, a renovator clearing rooms, or a caravan owner dodging the ranger — and the page has one job: an enquiry with the unit size and monthly rate already chosen. Everything on it, including the drawn storage unit, is procedural code — no photography, no raster images.
Concept
The aisle at mid-morning
Self storage sells calm: a clean, dry, numbered room that's yours for exactly as long as you need it. The art direction is the aisle itself — swept concrete, galvanised corrugation, and the one colour every facility owns: powdercoated roller-door orange. The signature element, the Unit Fit, answers the only question every storage customer has ("what size do I need?") by drawing the unit and stacking the customer's life inside it — then it hands the answer straight to the enquiry form.
Palette — measured, not assumed
The spec's contrast figures were treated as hypotheses and re-measured with WCAG relative-luminance arithmetic during Pass 1. The headline finding: roller-door orange #C2571F measures 3.88:1 on the concrete ground (the spec guessed ≈4.8:1) — so it carries surfaces and large marks only, never small text. Buttons deepen to #B34E18 (white label at 5.22:1), and orange text uses a minted door-ink #9C430F at 5.63:1.
The ink/line split holds throughout: zinc draws the unit and the dimension callouts, slate and gate-code ink carry every word.
Type
Saira 600/700 is the display face — an industrial-signage width that sets the dimension readouts ("3 m × 3 m"), prices and unit numbers like stencilled door plates. Manrope 400–800 is the workhorse: legible at 16.5px body on mobile, with enough weight range to carry chips, labels and the trust strip without a third face. The typographic bravery moment is the dimension readout swapping live above the drawn unit as the size chips fire.
The Unit Fit — techniques
The signature is a single <svg> rebuilt entirely by DOM script (createElementNS) on every state change:
- Cutaway projection. A front elevation with an oblique depth axis (17px, −9px per metre) — floor parallelogram, corrugated back wall, left wall, galvanised header and jambs. Size chips change the drawn width and depth; dimension callouts re-measure themselves.
- Greedy row packing. Each load is an item list (wardrobe, bed, sofa, fridge, washer, bike, boxes, tubs — the car chip draws a car in rear view) with real-ish widths in metres. Items pack first-fit into 1–4 depth rows; rows compress into a snug overlap when the load runs tight. The depth x-shift is damped to 35% so back rows never read as outside the door frame.
- Fit meter + overfill. Fill % = load m³ ÷ unit m³, shown on a jamb-mounted gauge with 25/50/75 ticks. Over 100% the gauge reads OVER and boxes draw tumbling past the door line — a note, never a forced swap.
- Daylight sweep. A gradient parallelogram clipped to the opening below the half-open curtain, ping-ponging on a smoothstepped 11s cycle. It never leaves the opening and opacity never drops below 0.58 — the thumbnail catches it alive at any instant. rAF delta is clamped at zero and capped (
dt = min(max(now−last,0)/1000, .05)). - Dual-speed redraw. First render staggers groups in at up to 1.05s; every subsequent chip tap redraws inside ~500ms via a
firstDrawflag. Handlers bump a sweep token before the state swap, so a rapid-fire burst of clicks can never leave an animation closed over a dead scene. - State probe.
window.__selfstorageexposes size, load, prepay, hardstand, rate, fill %, both notes and asettledflag — QA gates on state, never on seconds.
Honest pricing — the pinned model
Every figure is anchor arithmetic, verified against an independently reimplemented oracle in the test harness. Monthly, month-to-month, no lock-in. Totals are whole dollars by construction.
| Unit | Rate | Studio flat | 2-bed unit | 4-bed house | Car & garage |
|---|---|---|---|---|---|
| 1.5 × 1.5 locker | $95/mo | note | note | note | note |
| 3 × 3 | $265/mo | 56% — easy | 83% — snug, no note | 162% — note | 139% — note |
| 3 × 6 | $395/mo | 28% | 42% | 81% — no note | 69% — no note |
| 3 × 9 | $520/mo | 19% | 28% | 54% | 46% |
- Overfill note rule: the note fires exactly when the selected unit is smaller than the load's recommended size (studio→3×3, 2-bed→3×3, 4-bed→3×6, car→3×6). All 16 cells drive-verified against the oracle.
- Prepay (live on every unit and the hardstand): 6 months for the price of 5. The note is a template — "pay 5, store 6 — saves $<rate>" — so the saving scales honestly: $265 on the 3×3, $520 on the 3×9, $165 on the hardstand. The badge stays monthly.
- Hardstand ($165/mo): one drawn caravan bay. Size and load chips disable with the on-page reason ("hardstand is one bay, one price — the van doesn't care about shelving") rather than silently no-oping.
- Two designed price-less states: contents insurance prints a declaration, not a number ("arranged through your own insurer — we issue the storage letter your policy asks for"), beside the badge's ledger and again beside the form's total; business pallet & archive storage is "quoted to the volume and the turnover".
- Grid floor consistency: the services grid's "lockers from $95 a month" equals the Unit Fit's cheapest output.
Conversion decisions
- Above the fold at 375px: trade + suburb in the h1 ("Self storage in Bibra Lake"), reserve CTA, call button, and three trust chips — all inside the first viewport, verified by bounding-box assert.
- Signature in the thumbnail: at 1200×750 the drawn unit and the $265/mo badge on the roller door both intersect the first 750px — the price is part of the artwork, because the thumbnail is the commercial argument.
- Signature→form handoff: chips set the form's unit-size select and a summary line ("You're enquiring about: 3 × 3 unit — $265/mo"), so the enquiry arrives pre-qualified.
- Form fields are the trade's actual triage: name, phone, suburb, unit size, "when do you need it from?" (date), "what's going in?". Confirmation is a designed local panel — hidden on load and on empty submit, shown only after a valid submit, with a plain line declaring the demo. No fake network round-trip.
- Mobile sticky bar with call + reserve, solid dark background (no backdrop-filter — it composites wrong in headless Chrome, and thumbnails are headless captures).
- FAQ answers sell honestly: "what size do I need" points back at the Unit Fit; "is my stuff insured" repeats the your-policy/our-letter declaration.
Iteration log
Measure everything, trust nothing
- Re-measured every palette claim: the spec's ≈4.8:1 orange hypothesis measured 3.88:1 — demoted the pinned orange to surfaces, deepened buttons to #B34E18 (5.22:1 under white), minted #9C430F for orange text (5.63:1). Zinc measured 2.66:1 and stays linework-only.
- Screenshot review caught back-row silhouettes drifting past the right door jamb (the washer read as parked outside the unit). Fixed by damping the depth x-shift to 35% and clamping row width to the opening.
- The header tel link rendered empty below 640px — both its spans were hidden. Now a short "Call" label swaps in.
- The locker's small badge clipped "/mo" off its right edge; the price/suffix pair now anchors end/start around the centre.
Second reads and snappier hands
- Prepay now prints "PAY 5 · STORE 6" inside the door badge itself ("6TH MO FREE" on the narrow locker plate) — the deal lives in the artwork, the honest scaled note lives in the ledger.
- Fit meter gained 25/50/75 tick marks — it reads as an instrument, not a progress bar. Spill boxes moved onto the threshold and their caption clear of the width dimension (they collided in the overfill screenshot).
- Second-read detail: the painted unit number follows the size — L 15, U 33, U 36, U 39, BAY 07. "BAY 07" also moved out from behind the caravan wheel.
- Micro-interaction: chips compress 4% on press; toggles slide with a swift cubic-bezier.
375px, rapid fire, reduced motion
- 375px masthead verified by explicit edge comparison (wordmark right edge vs call-link left edge vs CTA) plus screenshot; no horizontal overflow on either page.
- Rapid-fire drive — eight control clicks in a single evaluate, no settle between — lands on the asserted end state with zero console errors, because every handler token-invalidates the sweep before swapping state.
- Reduced motion: no entrance stagger, no sweep loop — the daylight band parks mid-sweep at 0.72 opacity so the scene still reads lit.
- Chanel rule: removed the floor seam line — the parallelogram already reads as floor.
- Final harness: 75+ asserts green — the full 16-cell fit matrix against an independent oracle, prepay scaling on three rates, the hardstand disable matrix, empty/filled submit on
button[type=submit], JSON-LD allowlist, and zero console errors on every run.
Local SEO we'd implement for the real business
This demo deliberately ships no LocalBusiness, Review or AggregateRating structured data — fictional facts don't belong in a real search index; the live pages carry only WebPage/BreadcrumbList schema naming the demonstration. For a real client, schema.org has the exact subtype — SelfStorage — and we'd ship it with real NAP, geo, hours and a genuine review feed:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SelfStorage",
"name": "Boxline Self Storage",
"url": "https://www.example-boxline.com.au/",
"telephone": "+61 8 XXXX XXXX",
"address": {
"@type": "PostalAddress",
"streetAddress": "(real street address)",
"addressLocality": "Bibra Lake",
"addressRegion": "WA",
"postalCode": "6163",
"addressCountry": "AU"
},
"geo": { "@type": "GeoCoordinates", "latitude": -32.09, "longitude": 115.82 },
"openingHoursSpecification": [
{ "@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "08:00", "closes": "17:00" }
],
"priceRange": "$95–$520/month",
"areaServed": ["Bibra Lake","Cockburn Central","Success","Yangebup","Spearwood","Fremantle"],
"makesOffer": [
{ "@type": "Offer", "name": "3 x 3 storage unit",
"priceSpecification": { "@type": "UnitPriceSpecification",
"price": 265, "priceCurrency": "AUD", "unitText": "per month" } }
],
"aggregateRating": { "@type": "AggregateRating",
"ratingValue": "4.9", "reviewCount": "180 (from the live reviews feed)" }
}
</script>
The top-level type is the point: SelfStorage is a real schema.org LocalBusiness subtype — no need to settle for the generic parent. Ratings would be wired to the client's actual Google reviews, never typed in.
What would change for the real client
- Live availability from the management system. Real facilities run on Storman or SiteLink — the Unit Fit's size chips would show live "3 left" availability, and "Reserve" would create a genuine reservation (and provision the gate code) through the management API instead of a demo panel.
- Billing through Xero. Monthly storage is recurring revenue: direct-debit agreements, automated invoicing and the prepay-6 deal handled as a Xero repeating invoice with a credit, so the "6th month free" is bookkeeping, not a sticky note.
- Their photos and reviews. The procedural aisle proves the layout carries without photography — the real build would add the facility's own drone shot and a live Google reviews feed in place of the demo cards.
- Real compliance lines. Actual ABN, real insurance partner wording for the storage letter, and CCTV/privacy signage copy checked against WA requirements.