Whimsy · Website design & engineering

Made for Marketing

A home for a creative business, from the first impression to the first conversation.

I designed and built Whimsy’s website to bring consulting, media, marketing, and web development into one experience. The work has room to show its character, services explain what comes next, and a durable inquiry system supports the conversation.

Next.js / React / TypeScript / Cloudflare

Whimsy’s desktop homepage, pairing its introduction with colorful campaign artwork and featured work
Real work leads the experience.
The Whimsy homepage on mobile, with stacked content, consultation links, and a rearranged campaign collage
Desktop to mobile
My role
Design, architecture & implementation
The experience
Work discovery, service guides & inquiries
The foundation
Static pages + an event-driven contact service

Product thinking

Make a broad business
easy to understand.

Someone looking for a website, an ad campaign, or business advice arrives with a different problem. The site connects examples, service details, and project context so each visitor can find a useful next step.

  1. 1 Discover the work

    A curated gallery brings 20 featured projects into five categories. Visitors can narrow the collection before opening a full case study.

    Category filters → Project stories
  2. 2 Understand the offer

    Service guides connect the examples to scope, pricing, required inputs, and deliverables. The creative work has a practical business context.

    Examples → Scope & expectations
  3. 3 Start a conversation

    The contact page asks about goals, audience, timeline, budget, and existing materials. A “Not sure yet” option leaves room to work out the right service together.

    Project context → An informed inquiry

Visual system

One site.
Lots of personalities.

Whimsy’s campaigns range from seasonal events to food photography and business branding. I built shared navigation and page framing around layouts that adapt to each subject. Click an image below to see more of the project and how it was built.

Choose a visual design example
Holiday in the Halls page pairing event photographs with cranberry headings and mint panels
Website presentation · Open image for a closer look

Campaign artwork · Partner spotlights · Event coverage

Holiday in the Halls

The campaign ties together the public invitation, individual partner spotlights, and photography from the event itself. Cranberry, mint, and seasonal illustrations connect the pieces.

Build the campaign as a sequence

The page moves from the public invitation to individual partner spotlights, then closes with photographs from the event. That order shows how one visual campaign carried through promotion and into the real experience.

Explore the live case study

Selected artwork and photography from Whimsy’s project collection.

Application architecture

Static delivery.
Selective interactivity.

The content-heavy site exports HTML and assets for Cloudflare Pages. React handles the parts visitors interact with, while a separate Cloudflare Worker owns inquiry processing and email delivery.

Content

TypeScript records

Projects, selected collections, service definitions, and image metadata.

work-data.ts · content.ts
Composition

Next.js routes

Shared framing with dedicated layouts for individual stories.

generateStaticParams()
Delivery

HTML + assets

Prebuilt pages served from Cloudflare Pages, without a runtime Next.js server.

output: "export"

Content and presentation

A curated selection maps project slugs into gallery categories. Dedicated React components give selected case studies their own composition while reusing captions, navigation, and calls to action.

Client interaction boundaries

Gallery filters use local React state. The contact form manages sending, saved, delayed, and error feedback. These behaviors sit alongside pages composed at build time.

Responsive, discoverable pages

Grid layouts and breakpoints reflow imagery and text. Native radio filters, labeled inputs, live status regions, and project-specific metadata support navigation and discovery.

Inspect the frontend source

Full-stack implementation

A simple form.
A durable delivery path.

A contact form is part of the business’s front door. I separated saving the inquiry from delivering the notification, so an email delay does not have to become a lost conversation.

Whimsy’s contact page with a labeled inquiry form, project-planning checklist, service pricing, and a portrait of Kay and her service dog Kora
Project context, practical expectations, and a person behind the business.

Help people explain the need

The checklist asks for goals and existing materials. Service guidance and pricing help visitors frame the conversation before they send.

Confirm what actually happened

The form distinguishes a saved inquiry from delayed delivery or a failed request. A reference number gives the submission an identity.

Make recovery part of the design

The browser reuses its submission ID on a retry. The backend stores delivery state and has separate paths for retrying and retaining failures.

From submission to notification

Cloudflare Worker / D1 / Queues / Email
  1. Accept

    Validate the request

    Check origin, required fields, lengths, email format, and the honeypot.

  2. Persist

    Save the inquiry

    Write to D1 with a client ID and reference before confirming it is saved.

    Saved response → Browser
  3. Dispatch

    Queue the delivery

    Send an inquiry ID to the queue. The consumer loads the stored record.

  4. Observe

    Send & track email

    Store the message ID, then record delivery, deferral, or failure events.

Recovery path: delayed retries for transient send errors, a scheduled job for stranded inquiries, and a dead-letter queue for terminal send failures.

Built for interruption

Delivery semantics,
retries, and recovery

Retry delays

  1. 1 min
  2. 5 min
  3. 15 min
  4. 60 min

The browser creates a UUID and retains it when a request fails. The Worker looks up that client ID before inserting another inquiry. A D1 write precedes a successful saved response; a queueing failure can therefore return “saved, delivery delayed” without asking the visitor to start again.

The consumer retries temporary send errors after 1, 5, 15, and 60 minutes. A five-minute scheduled job republishes pending or queue-failed records and queued or sending records that have stalled for more than 15 minutes. Provider acceptance and actual delivery are recorded separately, making delayed or failed delivery visible in the stored inquiry state.

Request boundaries

Validation and request boundaries

The Worker accepts JSON POST requests from allowed origins, validates required fields and lengths, and uses a hidden honeypot field to discard basic automated submissions. Prepared D1 statements bind submitted values, and HTML email content is escaped before delivery.

The email binding restricts the sending and destination addresses, keeping inquiry notifications within the business’s configured delivery path.

Build-time decisions

Static export and image-delivery tradeoffs

Next.js generates the project and service routes at build time. Project metadata comes from the same records used for presentation, while specialized components own each story’s layout. Content updates require a new build and deployment.

The export uses Next.js images with unoptimized: true, so there is no runtime image-resizing service. Source dimensions, chosen assets, CSS composition, and loading priority matter. The gallery’s filters run locally in the browser; the contact Worker remains a separately deployed service.

From first impression to first inquiry

Creative work gets their attention.
The system handles what comes next.