← Back to web work
Web Development · Case Study · 2026

The Keyboard Board
From Empty Prototype
to Functional Product Site

8 pages, 10 wood finishes, a fully functional localStorage cart, a cart-to-contact inquiry pipeline, and a CSP that actually enforces itself.

8Pages
10Finish directions
315Lines of JS
0Fake claims
Overview

Two versions of the same site — and why the difference matters.

The Keyboard Board exists in two forms in this portfolio. The original student build — submitted as a class project — was a static HTML site with a visually appealing design, no functional cart, a contact form that posted to `#` and did nothing, a product page where "Add to Cart" buttons were decorative, and `shop.html` as a completely empty file. The design was good. The execution was a prototype in the truest sense: it looked like a product website without functioning like one.

The rebuilt version took that design and brought it to the standard expected of a launch-ready product concept site. The cart works. The form is wired. The Add to Cart buttons do something. The empty shop page was rescued. The security headers are correct. The sitemap is accurate. The OG images are absolute URLs. The fallback handles private browsing. The contact form pipeline carries a live order summary from the cart into the inquiry form.

Both the design direction and the product concept — a refined wood cover that turns a keyboard into usable surface space — were preserved completely. The rebuild was about making the site function as well as it looked.


The Product

A simple idea that deserved a site worthy of it.

Most musicians with keyboards in their home or apartment face the same constraint: the keyboard occupies a significant horizontal footprint and becomes dead surface the moment you're not playing it. You can't put a laptop there, you can't use it as a desk without risking damage, and it just sits there taking up prime room real estate while contributing nothing.

The Keyboard Board reframes the instrument as a surface opportunity. A fitted wood cover rests across the top chassis of the keyboard — not on the keys, but on the raised body surrounding them — creating a clean, stable tabletop. You use it for notes, a laptop, a coffee, cables, the small necessities of a working session. When it's time to play, you lift it off. The keyboard goes back to being a keyboard.

The concept is honest about what it is: a student-designed product idea that has not been through final engineering, weight-rating validation, or manufacturing. Every page acknowledges that. The announcement bar across the top of every page reads "Student product concept and functional web prototype" in the footer. Prices are presented as design decisions, not confirmed retail figures. That honesty is part of the design, not a disclaimer bolted on at the end.

"The original vibe stays intentionally minimal: warm wood, classical restraint, and a product that feels like it belongs in a real room."


Design System

Eight tokens. Two fonts. One coherent material identity.

The design system is built around a tight eight-token palette that earns its coherence because every color connects to the material identity of the product. There's no arbitrary accent color — every choice can be traced back to wood, warmth, espresso, cream, and gold.

--ink
--espresso
--gold
--gold-dark
--muted
--cream
--paper
--line

The typography pairing is Playfair Display — a high-contrast serif with classical proportions — for all headings, and Space Grotesk — a geometric sans with a slightly crafted quality — for body and UI text. Both are self-hosted as woff2 files with `font-display: swap`. The combination reads as premium without tipping into stuffiness. It fits a product that wants to sit in a bedroom or studio and feel like it belongs to the room rather than sitting in a tech startup landing page.

The CSS is 949 lines covering the full design system from tokens through components, with two mobile breakpoints (780px and 480px) and a `prefers-reduced-motion` block that disables hero fade animations and button transitions for users who've requested reduced motion at the OS level.

Playfair Display — headings Space Grotesk — body + UI Self-hosted woff2 font-display: swap clamp() fluid spacing prefers-reduced-motion --radius: 18px

The Cart System

315 lines of JavaScript that make the prototype actually work.

The most significant difference between the original build and the final build is the cart. In the original, "Add to Cart" buttons were `<button>` elements with no event listeners, no state, and no connection to anything. The cart page showed two hardcoded items — Walnut and Redwood — that appeared regardless of what the user had clicked. The checkout button was `type="button"` and did nothing.

The final build replaces all of that with a real client-side cart system built on `localStorage`, a product catalog object, and a pipeline that carries the order summary from the cart into the contact form inquiry. Here's what it does:

Product catalog. All 10 covers are defined in a single `products` object with id, name, price, finish, size, image, and alt text. Every piece of product data lives in one place. Updating a price means changing one number.
localStorage with proper fallback. `getCart()` wraps `JSON.parse` in a try/catch. `saveCart()` wraps `localStorage.setItem` in a try/catch with a `fallbackCart` in-memory variable — so the cart stays functional for the full session even when `localStorage` is unavailable (Private Browsing, storage-disabled contexts, quota exceeded). This is the correct pattern, not just catching errors and silently dropping the cart.
Live cart count in the nav. The cart link shows a pill with the current item count, updated every time something is added or removed. The pill has `aria-label="X items in cart"` so screen reader users get a meaningful announcement rather than a bare number.
Toast notifications. Adding or removing an item shows a `role="status"` + `aria-live="polite"` toast that announces the action to screen readers and auto-dismisses after 2.2 seconds. One toast element is reused and cleared rather than a new one being created on every click.
Dynamic cart rendering. `renderCart()` builds the cart DOM entirely from `localStorage` state. Quantity inputs use `type="number" min="1" max="25"`. Remove buttons carry `aria-label="Remove [Product Name]"` — not just "Remove" — so screen reader users know which item they're removing. An empty state with a browse CTA renders when no items are in the cart.
Cart-to-contact pipeline. The "Request Checkout Details" button writes the order summary to `sessionStorage` and navigates to `contact.html?cart=inquiry`. On the contact page, `hydrateContactCartSummary()` reads `sessionStorage`, displays a formatted order preview above the form, and populates a hidden `cart_summary` field that Netlify captures alongside the inquiry. A recruiter, stakeholder, or actual customer reviewing the form submission sees exactly what was in the cart.
Active nav state. `setActiveNav()` reads `window.location.pathname`, matches the current file to the correct nav link, and sets both `.active` and `aria-current="page"`. It handles the `shop.html` edge case by mapping it to the Gallery nav link so the active state is always correct.
315
JS lines
10
Product catalog entries
18
JS functions
0
External JS deps

Content Architecture

8 pages, each doing exactly one job.

Home — The product in one viewport. Hero image rotation, brand statement, three feature pillars, four featured covers with live Add to Cart, and a browse CTA. A visitor understands what the product is, what it looks like, and how to buy within seconds.
Gallery — All 10 finish directions as product cards. Every card has a name, image, description, price, and a live Add to Cart button wired to the cart system. A note above the grid explains that the cart is functional.
Shop — An identical product grid to the gallery, positioned as a "quick selection" view that rescues the old `/shop.html` URL from being a dead end. The description is product-facing, not internal documentation language. The JS maps `shop.html` to the Gallery nav link so the active state remains consistent.
About — Product story, design rationale, a four-step concept timeline, and the original infomercial video. The YouTube embed uses `youtube-nocookie.com`, `loading="lazy"`, `sandbox` attribute, and a `title` for accessibility — not a raw iframe paste.
Cart — Dynamically rendered from localStorage state. Handles empty, single-item, and multi-item states. Quantity controls with `type="number"`. Per-item remove buttons with descriptive aria-labels. Live order total with $12 flat shipping. Checkout button that routes the order summary into the contact form.
Contact — Netlify-ready form with proper labels, `type="email"`, a `select` for topic, honeypot spam field, and a `cart_summary` hidden field. Order preview renders above the form when arriving from the cart. Four contact detail cards frame the form context.
Contact Success — A confirmation page that exists and renders correctly, which is more than the original managed.
404 — Custom error page with two navigation paths back into the working site. On-brand copy: "This surface is not part of the collection."

The Finish Collection

Ten wood directions that make the concept feel like a real product line.

FinishPriceTone labelDesign tag
Birch$115Pale / calmSoft minimal
Ash$119Light / structuredModern utility
Oak$125Neutral / familiarEveryday classic
Walnut$129Dark / versatilePremium classic
Maple$139Light / cleanMinimal studio
Cherry$149Rich / polishedWarm interior
Redwood$159Warm / dramaticStatement finish
Mahogany$169Red-brown / refinedFormal room
Teak$179Golden / boldResort warm
Ebony$189Black / modernDark statement

Prices are graduated by character intensity — neutral woods at the entry end, statement finishes at the premium end. The logic is defensible and feels like a considered pricing strategy rather than random numbers. Each card's CTA is "Add to Cart," which is now meaningful — clicking it actually adds the item to a persistent cart that follows the user across pages.


Technical Standards

Deployment-ready, security-hardened, and accessible.

Content Security Policy that enforces itself. The CSP in `_headers` sets `script-src 'self'` and `style-src 'self'` — and because there are zero external scripts and the fonts are self-hosted, both directives are actually enforceable. No `'unsafe-inline'` anywhere. `frame-src` explicitly allows only YouTube and youtube-nocookie.com for the infomercial embed. `form-action 'self'` prevents form submissions to unauthorized destinations.
No duplicate security headers. The `[[headers]]` block was removed from `netlify.toml`. All security headers live exclusively in `_headers`. The netlify.toml contains only redirects — the wildcard 404 catch-all and the /shop clean URL. No maintenance trap where editing one file has no effect because the other file wins.
OG images and canonicals are absolute URLs. `og:image` points to `https://keyboardboard.netlify.app/images/4hero.jpg`. All canonical tags use the full production URL. Social link previews work. Search engine canonicalization is unambiguous.
Sitemap excludes session pages. `cart.html` and `shop.html` were removed from the sitemap. Cart pages are dynamic session surfaces with no content for Google to index usefully. The sitemap covers the five indexable content pages: home, about, gallery, shop, and contact.
fetchpriority is correctly scoped. `fetchpriority="high"` on the hero image tells the browser to prioritize that image over everything else — correct for the LCP element on content pages, wrong on the 404 and contact-success pages where the hero is decorative framing. The final build sets high priority only where it matters.
All images have descriptive alt text. Zero images missing alt across all 8 pages. The hero images describe what's actually in them ("Wood keyboard cover placed over a keyboard in a refined studio setting") rather than generic labels.
Self-hosted fonts with 1-year cache. Both Playfair Display and Space Grotesk are woff2 files in /fonts/, loaded via @font-face with font-display: swap. No Google Fonts CDN call. `/fonts/*` has `Cache-Control: public, max-age=31536000, immutable`.
Skip links before <header> on all 8 pages. Focus-visible styles on every interactive element: buttons, nav links, brand mark, quantity inputs, remove buttons, form fields.

Prototype Honesty

The most credible thing about this site is what it admits it doesn't have.

Every page footer reads "Student product concept and functional web prototype." The contact page notes "This is a student concept site, but the form is wired for Netlify deployment." The cart summary panel says "This student concept uses an inquiry checkout instead of live payment processing." None of this is buried in small print — it's integrated into the UI as honest framing.

What changed from the original prototype framing is that the site now earns that honesty by being actually functional in every dimension that doesn't require a real product to exist. The cart works. The form sends. The contact flow captures the order. The only thing missing is a real keyboard cover being manufactured and shipped — and the site is very clear about that.

The cart-to-contact pipeline is the key insight.

In a real e-commerce site, "Request Checkout Details" would route to a payment processor. Here it routes to a Netlify-hosted form that captures the full order summary as a hidden field submission. A stakeholder reviewing the site can add items to the cart, request checkout, and receive a professionally formatted inquiry through the contact form — with every item, quantity, and price included.

This is what separates a functional prototype from a decorative one. The interaction does something. The data goes somewhere. The feedback loop is complete even without a payment processor or a real product to ship.


Takeaway

The rebuild shows what it takes to move from design to execution.

The original build demonstrated taste. The final build demonstrates competence. Both matter — taste without execution produces beautiful things that don't work, and execution without taste produces things that work but nobody wants to use. The Keyboard Board's final state has both: a design system rooted in material warmth and classical restraint, and a technical layer that makes every interaction actually do what it appears to do.

The progression from original to final is also a useful case study in what "launch readiness" means for a product concept site. It doesn't mean having a real product. It means having a real cart system, a real form pipeline, real security headers, real accessibility, real metadata, and honest communication about what's prototype and what would be production. This site has all of those things.

The interaction does something. The data goes somewhere. The feedback loop is complete — even without a payment processor or a real product to ship.

THE KEYBOARD BOARD · PRODUCT CONCEPT · WEB DEVELOPMENT CASE STUDY · UPDATED 2026