A weekend-planning app that turns "I don't know, what do you want to do?" into an actual, timed plan — designed end-to-end in continuous collaboration with an AI pairing partner.
Every Friday, some version of the same conversation happens: "What do you want to do this weekend?" "I don't know — what do you want to do?"
The tools that already exist solve adjacent problems, not this one. Review apps and event listings tell you what's happening nearby, but leave the actual sequencing — what fits before what, how long driving takes, whether the place will even be open when you get there — entirely up to you. Maps apps are great once you already know where you're going. Nothing sits in the gap between a vague feeling ("something outdoorsy, not too far, back in time for dinner") and a plan you can actually walk out the door and follow.
Golden Hour is a swipe-based planner that closes that gap: swipe on activities that match your mood, and it assembles them into a real itinerary — drive times, opening hours, sunset cutoffs, and all — that two people can look at and just go.
Golden Hour is built around a simple asymmetry: one person usually initiates the plan, and someone else usually just wants to know where to show up.
Has a rough mood in mind ("outdoorsy," "low-key," "somewhere new") but doesn't want to open six tabs to turn it into a plan. Values speed and a sense that the logistics are already handled.
Gets invited into a plan already in motion. Doesn't need edit access — needs to know the schedule, the address, and what to wear. Once a plan is locked, their view should read like a itinerary, not a workspace.
I didn't start in a design tool. I started by writing down the problem, then moved as fast as possible into something I could actually interact with — because for a flow this dependent on state (swiped stops, drive-time math, locked vs. editable views), static frames hide more problems than they reveal.
Wrote a PRD and a technical plan first: what "done" looks like, what data a plan actually needs (stops, drive segments, timing, locked state), and where the product could get complicated later.
Version: MVP v1 · Author: Sakura · Date: 2026-07-28 · Platform: PWA (Vercel), mobile-first
Weekends get wasted not from lack of ideas, but from decision friction, mood mismatch, couple coordination, and Saturday-morning inertia. Existing tools solve discovery; none solve deciding, agreeing, and actually going.
Target user: Couples (and solo users) in a city they've "exhausted," who want low-effort, mood-matched weekend plans.
| Metric | Target |
|---|---|
| Weekends with a locked plan | ≥ 3 of 4 per month |
| Follow-through (locked → went) | ≥ 70% |
| Time from check-in to locked plan | < 5 min |
| Both partners complete Thursday check-in | ≥ 80% of weeks |
Thursday check-in → cards generated → swipe → match → confirm → Saturday nudge → Sunday recap.
In scope: accounts + partner linking, mood check-in, AI-generated cards + personal backlog, swipe-to-match, confirmation flow, leave-by notification, lightweight recap. Out of scope (v2+): photo journal, seasonality engine, streaks/gamification, veto tokens, API integrations (Places/Eventbrite), groups > 2.
Principle: ask only what can't be learned later. Target < 1 minute, 3 screens. Preferences are mostly learned from swipes and skip-reasons, not asked upfront.
| Step | Screen | Collect | Why |
|---|---|---|---|
| 1 | Welcome + sign up | Email/Apple/Google, first name | Identity, partner sync |
| 2 | Home base | Home location (city or pin) | All drive-time math |
| 3 | Partner invite | Share link/code — skippable ("solo mode, invite later") | Collaboration without blocking signup |
Do NOT ask at onboarding: budget, energy defaults, detailed preference rankings, schedule. These come from weekly check-ins and behavior.
Partner linking: invitee gets a trimmed onboarding (step 1 only — home base inherits from the couple, editable). A couple = shared "space"; each person keeps a private taste profile.
Push notification Thursday 6pm → 4 taps:
Weather for the weekend is fetched automatically — never asked.
5–7 cards per weekend, generated from: check-in answers × taste profile × weather × drive range × saved backlog (backlog items matching current conditions get priority + a "you saved this" badge).
Anatomy of a card:
No-match fallback (critical path): if zero mutual ❤️: (a) show each person their partner's top pick with "meet them here?" one-tap yes; (b) if still nothing, turn-taking: "It's Alex's pick this week" — tool tracks whose turn, chooser picks from their own likes, partner is notified, no veto. Turn-taking is the pressure-release valve that keeps no-match weeks from becoming no-plan weeks.
Same flow, different stops? Same 3-stop skeleton for solo and couple — solo just skips the sync/accept mechanics. One codebase path, a partner_linked flag branches steps 1 and 3.
Confirmation converts intention → commitment. Screen shows:
Saturday morning: one notification, 45 min before leave-by, with only the first step: "Leave by 9:40 — coffee stop at Verve on the way ☕." Not a checklist. Specificity beats inertia.
Cancel/reschedule — friction by design:
Sunday 7pm recap (30 sec): "Did you go?" → 👍/👎 rating → optional 1–3 photos → "That's weekend 7 of 2026 well spent." Skippable, never nagging (one notification, no re-prompts).
Anytime, either partner saves an idea (free text, or share-sheet a link/screenshot into the app). Each item auto-tagged: effort, season, weather-dependency, drive time. Items resurface as cards only when conditions match — "You saved this rainy-day museum in March. It's raining Saturday."
User (taste profile, home, range) · Couple (users[], turn_tracker) · Card (activity, drive_time, effort, cost, booking_flag, nudge, source: generated|backlog) · CheckIn (user, week, energy, craving, window) · Swipe (user, card, decision, skip_reason) · Plan (card, day, leave_by, status: proposed|locked|done|cancelled, rating, photos)
Shared photo journal + Sunday auto-recap reel · seasonality/scarcity engine ("3 golden-larch weekends left") · "12 free weekends before winter" counter · real event/places APIs · groups of 3+ · veto tokens & picker's-choice mechanics · preference-drift insights ("you both save food ideas but never go").
↑ scroll to read the full PRD
Color tokens, type scale, spacing — decided as reusable variables, not one-off values, specifically so the product could evolve its look without a full rebuild later. (This decision mattered more than I expected — more on that below.)
Reference images: mood-tracker (warm cream base, grain-gradient orb, sage accent pill, elevated yellow chart card) + Trove (soft lavender backdrop, floating white cards with visible elevation, rounded phone-native UI). Vibe: playful, lightweight, exploratory, exciting, chill.
| Token | Hex | Use |
|---|---|---|
--bg-page |
#F7F1E3 |
App background, warm cream (not stark white) |
--bg-section |
#EDE7D6 |
Secondary/grouped sections, subtle depth |
--surface-card |
#FFFDF7 |
Card background — warm white, floats above page |
--text-primary |
#211F1A |
Headlines, body — warm black, never pure #000 |
--text-secondary |
#6B675C |
Meta text, timestamps, captions |
--border |
#E4DCC8 |
Hairline dividers, unfilled input borders |
--accent-primary |
#F4F396 |
Pastel lemon-yellow — primary buttons, active states, progress, nav highlight |
--accent-primary-hover |
#E8E570 |
Pressed/hover state |
--on-accent-primary |
#3A3910 |
Text/icon on yellow fills — warm near-black, not white (contrast) |
--accent-secondary |
#6F8452 |
Sage green — demoted to secondary: success states, "trust"-style confirmations, outdoorsy accents |
Yellow is now the dominant, recognizable color — primary CTA buttons, active nav item, progress bars/rings, selected states, the swipe-right "yes" affordance. Use it generously and confidently, not as a small accent dot. Sage green steps back to a supporting role.
Gradient orb (hero moments only — Thursday check-in intro, match celebration, loading states): conic blend #F2C94C → #E8935A → #6FC3E0 → #7FB56B with subtle grain/noise overlay, like the reference. Used sparingly — it's the "delight" moment, not wallpaper. Never behind body text.
Color-coded, pill-shaped (border-radius: 999px), tinted background + darker text of the same hue — never black text on a colored pill.
| Vibe | Background | Text/icon | Icon |
|---|---|---|---|
| Outdoorsy | #E1EAD3 |
#4C6B34 |
tree / mountain |
| Foodie | #F6E0C8 |
#A85A22 |
bowl / utensils |
| Cultural | #E9DFF2 |
#6B4A94 |
ticket / palette |
| Cozy | #F1DFDA |
#A8604A |
flame / cup |
| Active | #FADADA |
#C23B34 |
bolt |
Effort tiers reuse this language: 🟢 Chill = outdoorsy green tint · 🟡 Half-day = foodie amber tint · 🔴 Big weekend = active coral tint. Keeps the palette closed instead of adding a third color system.
Inter, throughout — no serif, no secondary display font.
| Style | Weight | Size | Use |
|---|---|---|---|
| Hero | 800 | 32–40px | "A brighter day ahead" moments — check-in intro, match celebration |
| Headline | 700 | 22–24px | Card titles, screen titles |
| Body | 500 | 16px | Card copy, buttons |
| Meta/label | 600, uppercase, tracked +0.02em | 12–13px | Drive time, effort tier, timestamps |
Cards float on the cream/lavender background with soft, warm-toned shadow — never a cold gray shadow.
background: var(--surface-card); border-radius: 24px; box-shadow: 0 4px 16px rgba(33,31,26,0.06), 0 1px 2px rgba(33,31,26,0.04);box-shadow: 0 12px 28px rgba(33,31,26,0.14); — lifts further, like picking it up.Glass/blur panel style was explored and dropped for MVP — sticking with the single solid warm-white card elevation everywhere, including nav bars and overlays.
Swipe cards should spring, not snap — slight overshoot on release, matching the playful tone. Match celebration = brief gradient-orb pulse, not a modal interrupt.
↑ scroll to read the full spec
First pass as individual React components — swipe deck, itinerary timeline, stop detail — to work out the data model and interaction logic in isolation.
Reconstructed from the original React components for this write-up — not literal screenshots of the app.
Consolidated everything into a single interactive build covering the full flow — onboarding through check-in, swiping, itinerary, stop detail, and lock-in — so I could test the experience as a whole, not as disconnected screens.
From there, every design decision — a color, a line break, a font pairing, an interaction bug, an accessibility fix — happened directly on the running prototype, in dialogue with Claude, dozens of rounds, each one verified before moving to the next.
My first version required users to explicitly "lock in" a plan before it appeared in their itinerary — modeled loosely on a checkout flow. In practice that added a step with no payoff: the plan already exists the moment you've swiped on enough stops.
I redefined the model so any in-progress plan shows up immediately and stays editable. "Locking" became purely about finalizing a plan for sharing — it switches the view to read-only (no delete, no edit, invite becomes share) rather than gating visibility in the first place.
Once plans didn't require locking to exist, people could reasonably have two unfinished plans for two different weekend dates at once. Rather than surfacing every plan in a scrolling list (simple, but noisy for the 90% case of one active plan), I added a small dropdown next to the date header, with the closest unlocked plan shown by default.
The tradeoff: multi-plan support is one tap deeper than a flat list would be. I chose that because the common case — one plan — stays completely uncluttered.
The most valuable shift wasn't speed. It was working directly on something real instead of a representation of something real.
I never handed off a static mockup and waited for it to become interactive. Every design call — a spacing value, a font pairing, a color, an interaction — was made directly against a running prototype, so I was always evaluating the actual thing, not a stand-in for it. That collapsed a loop that's normally split across a design tool, a handoff doc, and an engineer: I could say "this gradient doesn't read" or "the shadow is still the old blue" and see the real fix in the same conversation.
I made the calls on what felt right, what was confusing, what wasn't accessible, down to "move this 12px down." Claude handled the code, and — critically — went looking for every other instance of a problem I'd only pointed at once, like tracking down all four leftover blue buttons after I'd only flagged one.
Each round ran through an automated regression suite simulating the full flow — check-in, swipe, itinerary, detail, delete, lock-in — plus syntax and byte-diff checks on the underlying code, before I ever saw the result. Fast iteration didn't mean fragile iteration.
The pointer-capture bug on the maps button wasn't something a prompt like "fix the button" could have solved by luck. It took reasoning through browser event order — the kind of debugging I'd normally need an engineer for.
As a designer, not an engineer, that meant I could ship something with real state — locked vs. editable plans, multi-date logic, drive-time math — that would normally require a dev partner just to be able to critique properly, let alone finish.
interact with me!