Skip to content
2026 NEW · SUPERHERO HOTEL

Superhero Hotel Booking

Rebuilding Superhero Hotel's two booking flows, the 4-Week Stay and the nightly Day-by-Day, around one rule the industry keeps breaking: never let the interface lie about price, scarcity, or time.

TL;DR

Role
Senior Product Designer, sole designer end to end, research through production code
Team
Christian Peters (founder, product direction), Michalis Vasileiadis (backend engineering), Liz (front desk, operational ground truth)
Timeline
June 26 to July 10, 2026, about two working weeks across three calendar weeks
Stack
Next.js App Router, TypeScript strict, Tailwind v4, shadcn/ui, react-day-picker, Stripe PaymentElement, Playwright for the E2E suites
Outcome
Both flows (4-Week Stay and nightly Day-by-Day) rebuilt around honest price, scarcity, and time. The fabricated scarcity counter is gone, replaced by real best-window pricing the founder approved in two live reviews. Delivered as review-ready pull requests with 31 green end-to-end scenarios, and the research surfaced three live production bugs along the way. The pricing build is on hold pending a roadmap decision, so no live metrics yet.

The problem

Superhero Hotel sells a fixed 28-day stay to startup founders visiting San Francisco's Frontier Tower. The founder's brief named four problems. Pick a start date near the edge of the calendar and your checkout month never rendered, so guests committed to a stay whose end they had never seen. The picker itself was a free date-range control strapped onto a fixed-length product. He wanted the flow to propose optimal start dates instead of accepting arbitrary ones. And arbitrary dates were expensive in a way nobody was tracking.

You don't see it if across different months… you can't even see the end date… the two-month window is not a good thing.

One guest leaves July 28, the next arrives August 10: 13 nights nobody can sell. Across a hotel's worth of rooms, that is the difference between a packed calendar and a leaking one.

Walking the live flow on video, my audit grew those four problems into a catalogue of fourteen. The ones the brief didn't name were about trust: the flow showed “Only 2 rooms left” counters that were random numbers, capped at 3 by design, and payment was full and non-refundable, disclosed late. My read: founders were at least as likely to abandon at trust as at calendar mechanics.

14problems catalogued. 4 named in the brief, the rest I surfaced walking the live flow.

Named in the brief

4
  • The calendar hides the checkout. The two-month picker never advances, so a later-month start puts the checkout in a third month that never renders. On mobile, only one month shows at all.
  • A free date-range picker strapped onto a fixed 28-day product, implying you can pick any two dates.
  • The flow accepts arbitrary start dates instead of proposing the optimal ones.
  • Arbitrary starts strand inventory: one guest leaves on the 28th, the next arrives on the 10th, and 13 nights go unsold.

Surfaced in my audit

+5
  • Fabricated scarcity. “Only N rooms left” was a random 1 to 3 that re-rolled on every refresh; git blame proved it was capped on purpose.
  • Full, non-refundable payment, disclosed late, right at the moment of commit.
  • The nightly widget priced before tax and duplicated the entire guest form.
  • That same widget dead-ended on sold-out dates instead of offering an alternative.
  • A rate-tier inversion in the live prices: six nights totalled less than five, $766 against $1,200.
The brief named four. These are the ones I surfaced that mattered most.

My role

Sole designer, end to end: the research, both flows, the founder feedback and review sessions, an interview with front-desk operations, and the handoff to backend engineering. Every design decision and every QA catch was mine, including the pricing inconsistency below, the step-overload call, and the copy that had to be rewritten. Claude helped synthesize the competitor research. I verified everything I shipped by breaking the flows in the browser at five viewports and tabbing through every step.

Two working weeks from brief to handoff, June 26 to July 10, 2026.

Discovery

Start from the live flow, not the brief

Instead of designing against the founder's four problems, I started from evidence: I walked the live flow on video and mobile screenshots, read the git history, and probed the production APIs read-only. Fourteen catalogued problems came out, and the most interesting one looked like a bug and wasn't. The scarcity counter was fabricated deliberately: the founder's own commit capped it at a random 1 to 3 because raw inventory (“36 rooms left”) weakened the signal. That finding set the shape of the whole project: the business goals were real, the mechanisms were the problem.

Who's booking

One primary user, defined in the PRD (product requirements doc) and held to: the founder relocating to Frontier Tower for a working stint. They think in months and rough windows, not check-in/check-out dates, so “which month” comes before “which dates.” They're committing thousands sight-unseen, which is why non-refundable prepay next to fake scarcity reads as risk, not urgency. And their flexibility on start dates was an assumption I flagged for validation rather than a fact, so exact-date entry stayed first-class instead of being designed away. The tourist on a short, specific-date stay was explicitly deprioritized to the nightly track.

Empathy map: The Founder

PRIMARY PERSONA · LONG-STAY, STRATEGIC · RELOCATING TO OR VISITING FRONTIER TOWER FOR A WORKING STINT

  • Founder / operator / builder
  • Often referral-driven
  • Time-poor, certainty-seeking
  • Some date flexibility, to validate

Says

  • “I'm coming to SF around August for about a month.”
  • “Just need somewhere to live and work, sort it for me.”
  • “Is this the real price, or does it balloon at checkout?”
  • “I'll be here for the cohort / demo day.”

Thinks

  • I think in months and rough windows, not check-in/out.
  • Decide the month first; exact dates can come later.
  • I have some flexibility, but my lease / flight may not.
  • Don't make me hunt for a bargain; just be fair.

Does

  • Arrives via referral; trusts the network.
  • Compares a few options fast, then commits.
  • Books a working stint near Frontier Tower.
  • Picks the guided ‘best’ option if it's clearly fair.

Feels

  • Time-poor, wants certainty over endless optionality.
  • Wary of dynamic pricing and hidden fees.
  • Trust-sensitive: committing thousands sight-unseen.
  • Reassured by transparency and a real confirmation.

Pains

  • Calendar defaults to a near-over, mostly-booked month.
  • Range picker implies ‘pick any two dates’ for a fixed stay.
  • Teaser price, then about 30% reveal-shock at checkout.
  • ‘Confirmed’ that isn't; refund / cancellation anxiety.
  • Fake ‘only N rooms left’ erodes trust on refresh.

Gains

  • Pick a month, see a few optimal 28-day slots, done.
  • Best-priced slot framed as a carrot, transparently.
  • All-in (tax-incl) pricing kept in the new slot list, already shown; don't regress.
Rebuilt from the discovery board.

What the front desk knew

Not all of the research was desk research. I sat with Liz at the front desk (we spoke in Taglish) to understand her side of the counter when founders book. Two operational realities came out of that conversation.

Occupancy is a policy, not a room property. Founders get one guest per single room; partners and married couples are allowed two; the OTAs (online travel agencies) sell the same rooms at two per single and four per double. The direct flow now caps occupancy at her numbers, not the OTA's, and the guest copy that had framed the second guest around “partners and married couples” got rewritten for the actual customer: “Bringing your partner? You'll share the Suite's king bed. Traveling with a co-founder or friend? The Double has two separate beds.”

She also confirmed what I'd found in the live Stripe states: nothing holds a room while a bank transfer settles. That confirmation turned a copy problem into a product decision (below).

What the industry actually does

Two research waves ran before any pricing UI got designed: published UX and pricing evidence first, then a competitor teardown with review mining. The findings converged. Nobody in long-stay hospitality uses fabricated scarcity. Blueground runs airline-style dynamic pricing worded entirely as savings. And the industry's real trust failures cluster after booking (cancellations, refunds, hidden fees), which we logged as a watch-out.

When gap pricing came up, I pushed for rigor over instinct: research other providers first. The revenue-management tools (PriceLabs, Beyond, Wheelhouse, OwnerRez) treat orphan gaps with discounts of 20 to 35% and prevent them with stay restrictions; nobody surcharges the booking that creates the gap.

Industry practice: orphan gaps get 20–35% discounts and prevention via stay restrictions. Nobody surcharges the gap-creating booking. The penalty framing we almost shipped would have been an outlier.

The same research named the endgame pattern (price-per-date calendars, the Google Flights model) as the next iteration once live pricing flows, and fed the backend brief: score both edges of the 28-day block, the arrival gap and the trailing fragment.

I also studied Airbnb's flexible-dates system from recordings: the continuous-scroll calendar that solves our hidden-checkout bug, all-in pricing, and a “free cancellation” selling point this non-refundable product can't match, a competitive gap worth knowing rather than hiding. A read-only scrape of the live nightly rates across six rooms and six stay lengths surfaced a price inversion (6 nights cheaper than 5 in total) that went straight to the founder.

The 4-Week Stay

Urgency without lying

The founder's deliberate fake counter changed my job from “delete the dark pattern” to “give the business goal a mechanism built on real inventory.”

The replacement makes urgency a property of the offer instead of a counter: the flow presents a handful of real, gap-free “best windows” each month at the lowest price, and windows that strand empty nights cost visibly more, with the reason written next to the price (“Starts 4 nights later than the best window, so it's priced a little higher”). Scarcity became “the good windows are genuinely few,” which has the advantage of being true.

The founder had originally asked for a penalty framing: prices increase as you drift from optimal. Competitor research supported flipping it. Blueground runs the same economics as “save by booking closer to the availability date,” pricing the operator's need as the guest's discount so both sides win the same transaction. I presented that flip as his call to make, with the evidence, rather than just shipping my preference. It became the model he approved:

High occupancy for us, best price for them.

The 4-Week Stay opening step: month-first chips, then the best gap-free windows for July, a BEST PRICE badge on the cheapest with its anchor struck through and “save $80”, and the next window reading “+$80 vs best” with the reason written beside it.
Month-first, then the best windows, priced honestly against the anchor.

Guide only where the constraint is real

Curated windows make sense in busy months. But in a wide-open month, “3 best windows” is fake curation: every start date is equally optimal. The founder spotted it in review and sketched the answer: when everything is open, just show the calendar.

For September there is no such thing like an ideal start date.

My first build gave open months their own embedded calendar. Then I asked the question that killed it: with an exact-date calendar one tab away, isn't this redundant? It was. The shipped version makes wide-open month chips navigational: tap “October · Wide open” and you land on the one calendar, scrolled to October, with a banner explaining that every start date gets the best price. One calendar in the whole flow. Which months flip between curated and open is decided by the backend per month, so the interface adapts as occupancy grows without a redesign.

That one calendar is also where the brief's first problem dies. It scrolls continuously (the Airbnb pattern from the research) instead of paging two fixed months, the full 28 days shade across month boundaries, and check-in and checkout stay pinned in the summary below it. Nobody commits to an end date they have never seen.

Wide-open months skip the curation and just show the calendar.

The date decides the price, never the tab

Testing my own flow, I picked July 9 in the flexible tab: $1,900, best price. Then I picked the same July 9 on the exact-date tab: $1,980, standard rate. Same stay, two prices, depending on which button you had clicked. Nobody had specified this case, and it would have shipped.

The fix became a rule with a name: the date decides the price, never the tab. An exact-date pick that matches an optimal window now bills that window's price; a suboptimal pick shows its real uplift and offers a one-tap “Best-price start” upgrade. The rule then outgrew the frontend: it went into the backend handoff as a contract requirement that every number a guest sees, taxes included, comes from the pricing API.

The exact-date tab with a suboptimal start selected: the 28-day range shades across the August to September boundary on the continuous calendar, check-in and checkout pinned in the summary, which shows the standard rate and its real uplift with a one-tap “Best-price start, save $80” row offering the nearest optimal date.
A suboptimal date shows its real uplift, checkout always in view.
The 4-Week Stay, end to end.

The Day-by-Day

Two flows that behave like twins

The hotel's nightly track (1 to 27 nights) ran through an embedded third-party widget: prices shown before taxes, duplicated guest forms, and dead-ends on sold-out dates. I brought it in-house as the 4-week flow's sibling: same steps, same validation behavior, so a guest who learns one flow has learned both.

The parity ran both directions. When I judged the 28-day flow's first step overwhelming (dates, guests, and rooms stacked on one screen), the fix came from the nightly flow's structure: room selection became its own step. When the nightly flow got press-to-validate (an always-enabled button that marks every missing field and focuses the first one), the 28-day flow got it the same day. I had originally deferred inline validation to keep the prototype moving; an audit I ran against the flow ten days later named that deferral its weakest point, and I reversed it the same day.

The Day-by-Day “Pick your room” step: rooms as full cards, price-sorted, the cheapest that fits wearing a Recommended badge, each with a photo gallery and amenity chips.
The room step both flows share: price-sorted, the best fit flagged Recommended.

The widget's failure points, handled

The old widget's dead-ends became moments the new flow designs for:

  • Sold out is caught at selection, not after you've committed to a room. A “We're full for these dates” card offers two one-tap alternative windows of the same length, with WhatsApp and email as the human fallback.
  • 28 nights or more steps aside. The nightly path hides and a routing card hands you to the 4-Week Stay flow, carrying the check-in date you already picked.
  • All six room categories render as full cards, price-sorted, and the cheapest room that fits your party wears a Recommended badge. Groups get per-category room steppers with a live capacity tally (“2 rooms · sleeps 4 · Room for 4 of 7 guests”), and Continue stays gated until everyone fits.
  • Two-tier pricing became an honest hint. I scraped the live rates across six rooms and six stay lengths to model the real tier break, then wrote it next to short stays: “Stays of 6 nights or more get a lower nightly rate.”
  • A declined card is a designed state. A destructive banner, the form preserved, a retry that works, tested against Stripe's decline test card.
The “We're full for these dates” card, caught at date selection: two same-length alternative windows on either side, each one tap to apply, with WhatsApp and email as the human fallback.
A dead-end became a designed recovery.
The Day-by-Day, the nightly twin.

Explored and killed

Built, then killed by taste

  • An Airbnb-style two-mode picker with ±3 days flexibility chips. Built, then cut: the flexibility math complicated the packing model for marginal benefit. The simpler month-first flow survived contact with the founder twice.
  • Collapsible room rows. I proposed showing only the recommended room expanded. It passed every automated test, and I still killed it after seeing it: burying rooms behind a tap made the page tidier at the cost of trust. All six rooms render as full cards.

The invisible work

None of this shows up in a screenshot. It shows up when you tab through the flow, refresh mid-booking, or book from the wrong timezone. It is most of what separates a prototype from something you would trust with a card.

Hotel-time everywhere

“Today” is computed in San Francisco time regardless of the visitor's timezone. A founder booking from Manila at 2am sees the same calendar the front desk sees. A subtle server-side variant of the same bug (a long-running process freezing “today” at boot) got the same treatment.

Copy that never overpromises

When I found that Stripe couldn't actually hold a room while a bank transfer settled, I stripped every “we're holding your dates” line from the flow. When no honest version survived, we cut bank transfer entirely rather than ship a promise the backend couldn't keep.

Focus that follows intent

Tap a wide-open chip and focus lands on the banner that explains where you are. Step changes focus the new heading, and the photo lightbox traps Tab. None of it shows up until you put the mouse down and Tab through the flow.

State that survives

Refresh mid-booking and your draft restores. Browser Back steps backward through the flow instead of ejecting you. “Edit booking” from the payment step returns you to the start with nothing retyped. The exception is card details, which the flow never writes to storage.

Where it stands

Both flows were delivered as pull requests and in review at handoff, with the pricing algorithm assigned to backend engineering against my spec. What stands behind them:

  • The founder approved the flow in two live reviews; both of his change requests (current-month availability, windows visible on load) shipped the same day.
  • I briefed backend engineering against my handoff spec, and the pricing algorithm was assigned to be built against the contract it defines; that build is on hold pending a roadmap decision, so there are no live results yet.

31 automated end-to-end scenarios across the two flows, green at handoff, covering the full booking paths, validation, focus management, and a 320 to 1920px responsive sweep.

WCAG (Web Content Accessibility Guidelines) 2.2 AA throughout: contrast measured to clear the bar on muted text, 44px touch targets, and a reduced-motion alternative on every animation.

  • Research along the way surfaced three live production bugs (the hidden-checkout calendar, a schema.org price rendering “$undefined/night” to Google, and a rate-tier inversion where 6 nights cost less than 5), all documented for the team.

In hindsight

What this project taught me

Make data access a condition of the brief. We asked for funnel analytics in week one and designed three weeks without them; every “where do founders actually drop?” debate ran on judgment instead of evidence. Judgment held up, but I'd rather have known.

Two habits this project hardened. Check history before overriding: three things that looked like obvious bugs (the fake counter, the penalty pricing, the full prepay) were the founder's deliberate decisions, and the git log proved it. I brought each counter-proposal back with evidence and kept the decision where it belonged, with the business owner; all three ended in agreement. And hold the brief steady under dramatic findings: when competitor research surfaced a reframe (“the real risk is post-booking trust”), I tested it against the brief, confirmed the founder's direction was sound, and filed the reframe as a watch-out instead of a pivot.

Credits. Christian Peters (founder): product direction, pricing model, two rounds of live review. Michalis Vasileiadis: backend engineering and the algorithm build. Liz (front desk): operational ground truth on occupancy policy and payment reality.

Next project

2022 · Mobile

Compensatory Time Off

XD+ by BeeBee Rodil