Scout — Full Product Context → feature documentation

New Home screen

The new Home (scout://, behind new_home_screen, default on), on one screen that never scrolls: standing in a City Challenge, that city's ring and its next stop; anywhere else, the nearest patch you have not collected, floating over its place photo. Under either, Go collect it and four doors: Map, Collections, Patches, Trips.

Summary

The new Home is a collecting-first replacement for the field-guide Home, on the same route (scout://, mobile/app/(drawer)/index.tsx). It puts patch art at the centre and, since 2026-10-08, it is one screen: nothing scrolls. From top to bottom:

  1. The top bar, "Corners": a glass menu button in the left corner, the place you are in as one quiet centred line ("Cupertino, CA"), and a glass bell with its unread count in the right corner. Profile is not on Home; it is the avatar at the top of the drawer.

  2. The hero, which aims for 80% of the screen's height and gives some back on a phone too short for everything. It asks one question first: are you standing in a City Challenge?

    • In a City Challenge (within placeModeRadiusMiles, default 2, of one of its stops), the hero is that city: the city's own ring, the same one its City Challenge page draws, sized to the room the hero leaves it (358pt at most, about 200pt on an iPhone SE). The next stop's patch floats in the middle of the ring, its place photo lies behind it, and a satin arc runs over what you hold. Under the ring: "You're in a City Challenge", the city's name, "5 of 15 collected · 10 to go", then one line, Next stop and the stop's name, and its facts. Once the city is done, the ring says "Complete" and the line reads Your next patch: the nearest uncollected patch anywhere.
    • Anywhere else, the hero is the nearest patch you have not collected, in the ring header's own look without the ring: the place's photograph behind it (tinted, fading into the black, the same RingHeaderField), and the patch, floating, like the unlock celebration's patch, at most 30% of the screen's height. Under it the ring header's centred title: the patch's campaign motif over its campaign name in that campaign's accent, then the name (two lines at most) and the facts.
  3. Go collect it · info, one row under either hero. Go collect it opens the Compass aimed at the patch, so there is no separate compass button (removed 2026-10-09). It is a flat button in the next patch's campaign colour (a State Parks patch is green, a Ghost Adventures one lavender). A patch's themed campaign wins over the City Challenge it sits in: Winchester Mystery House is lavender even from San Jose. Only a patch with no themed campaign wears the City Challenge brass.

  4. The action bar: four doors, the same four for everyone, each an icon in a ring of that same campaign accent, its name, and one live line:

    • Map: "14 within 10 mi" (uncollected real stops within 10 miles), "None within 10 mi", or "Explore nearby" with no location.
    • Collections: "12 in progress" (collections started and not finished), or "Start one".
    • Patches: "41 collected" (every patch you hold, imports included), or "Collect your first". It opens My Patches, the same place as the drawer's My Patches row. (Until 2026-10-09 this door was Badges, "32 one visit away"; Alan swapped it so your collected patches are one tap from Home.)
    • Trips: "Plan a day trip". It opens /trips, the same place as the drawer's Trips row (the new Trips, or Day Trip with trips_v2 off).

    The bar sits in the middle of what the buttons leave and never shrinks. On a short phone, the hero gives the room back instead.

The 2026-10-08 one-screen layout follows mobile/research/home-fit-lab.html (bar A, Corners, Liquid glass, hero 80% and patch 30%; the picks are recorded on the page). Before it, the same day, the City Challenge ring and the full-bleed hero came from home-ring-lab-r2.html and home-ring-lab.html round 5 (variant B3). The very first version was built to home-gamified-lab.html, variant B. The field-guide Home it replaces is kept intact as the flag-off path (see discovery-surfaces).

Status

Built, behind new_home_screen, default ON. The flag is in both registries (mobile/src/config/feature-flags.ts:39, backend/src/admin/feature-flag-definitions.ts:40). The route picks the screen on every render (mobile/app/(drawer)/index.tsx:19). Because the client default is also ON, a cold start draws the new Home before the server answers. Only a server that has turned the flag OFF swaps to the field-guide Home, once, when flags land.

The 2026-10-08 work shipped in v1.1.103 (7c62da12, 26f715b2; live on the App Store in 1.1.107): the City Challenge mode, the floating hero, and then the one-screen layout with the action bar. Builds before 1.1.103 show the earlier scrolling new Home. It changed the new Home in place, with no new flag: new_home_screen still chooses between this screen and the field-guide Home.

The rarity in the hero's facts renders only for a patch with a tier. Rarity is live on prod (patch-rarity), and almost every real place carries one, so it almost always shows, usually as Common.

User-facing surfaces

Surface Where testID
Top bar (Corners): menu, the place line, the bell with its count ("9+" past nine) mobile/src/components/home-new/CornersTopBar.tsx:24 — Scout.TopBar with glass IconButtons; the count is MessageBell's own UnreadBadge nh-topbar, fg-menu, nh-place, fg-messages, fg-messages-badge
City Challenge hero: the city's ring fitted to its box, "You're in a City Challenge", the city's name, "5 of 15 collected · 10 to go" / "All 15 patches collected", the Next stop / Your next patch line and its facts mobile/src/components/home-new/CityHero.tsx:110 nh-city-hero, nh-city-ring, nh-city-kicker, nh-city-title, nh-city-progress, nh-city-next, nh-city-facts
A patch on the city's ring opens that patch (/patch-modal/<id>) cc-ring-patch-<id>
The Next stop line opens that stop (/patch-modal/<id>) nh-city-next
Full-bleed hero (outside a city): photo, the patch floating on it, the campaign motif and name, the patch's name, rarity + facts ("1.0 mi SE · 3 min drive · State Park"). Tapping it opens the patch mobile/src/components/home-new/HuntHero.tsx:48 nh-hero, nh-hero-art-box, nh-hero-art, nh-hero-kicker, nh-hero-title, nh-hero-facts
Go collect it (Collect it standing on it) · info, under either hero HuntHero.tsx:110 (HeroCtas). Go collect it opens the Compass on that patch (/compass?patchId=); info opens its detail. No compass button: Go collect it is the compass nh-hero-collect, nh-hero-info outside a city; nh-next-collect, nh-next-info in one
Action bar: Map → /map, Collections → /campaigns, Patches → /my-patches (my-patches; /browse-patches?status=collected with my_patches_screen off), Trips → /trips mobile/src/components/home-new/ActionBar.tsx:17; routes NewHome.tsx:68 nh-action-bar, nh-door-map, nh-door-collections, nh-door-patches, nh-door-trips
Empty hero (permission off / nothing to collect) the field-guide Home's HeroEmpty, shared, in the hero's place fg-hero-empty
Screen mock gallery scout://dev-screen-mock/new-home: seven states, including in a City Challenge, the city complete, first day and location off (mobile/src/dev/mocks/new-home.tsx) —

The root keeps fg-home / fg-home-skeleton, the Maestro "home loaded / still loading" anchors, so a flow that waits for home works under either flag value.

How it works

Everything is derived on the device from synced content and your collected set, with no request of its own, in the view model NewHomeViewModelImpl (mobile/src/components/home-new/NewHome.tsx:120). The derivations are pure functions in mobile/src/components/home-new/selectors.ts, fit.ts and CityHero.tsx:

  1. Where you stand: the field-guide Home's own proximity selector, selectHomeContext (NewHome.tsx:162). It returns place when the nearest City Challenge stop is within placeModeRadiusMiles, and Home takes the city as its hero (NewHome.tsx:185). Within the wider cityChallengeRadiusMiles band, the city only ranks first among the collections that colour a patch. There is no park mode, so no containment check.
  2. Open patches: rankOpenPatches (selectors.ts:45) ranks every uncollected patch in the whole catalog, nearest first, with no radius. Everything the screen sends you to or counts as a destination (the hero, the next stop, the Map door) is narrowed to real stops with filterRealStops; see Edge cases.
  3. The City Challenge hero: buildCityHero (CityHero.tsx:68) builds the ring with the City Challenge page's own pure builder (buildCampaignRingScreenData, mobile/src/components/campaign/CampaignRingScreen.tsx) and draws it with the page's own dial (RingDial), so the two can't disagree. The next stop is the nearest uncollected real stop among the city's members. Once the city is done, or only city/state containers are left, it is the nearest real stop anywhere, labelled "Your next patch". With nothing open anywhere there is no line and no button row.
  4. A target: targetFor (selectors.ts:209) is the one shape both heroes and the button row read: name, art, photo, rarity, facts (heroFacts, selectors.ts:94: distance + heading, walk or drive time, type, or just "You're here"), and its campaign (themeOfPatch, selectors.ts:188: the family, motif and kicker that colour it).
  5. The doors: selectHomeDoors (selectors.ts:250, called at NewHome.tsx:210). Map counts real stops within 10 miles; Collections counts collections with 0 < collected < patchCount; Patches counts your collected set (useCollectedPatchIds, imports included, as My Patches lists them); Trips is fixed. No location fix → Map says "Explore nearby".
  6. The fit: homeFit (fit.ts:10) turns the window height into the hero's flex basis (80%) and the patch's cap (30%). The hero slot may shrink (flexShrink: 1, minHeight: 0); the action area may not, and its bar slot keeps 22pt above and below (NewHome.tsx:308). Those slot styles live in one place, mobile/src/components/home-new/layout.ts, which the loading skeleton uses too. So on a phone where everything does not fit, the hero gives the room back, the patch shrinks inside it, and the doors keep their air. The City Challenge ring measures the box the title leaves and is sized by ringFit (fit.ts:16): as big as the box allows inside the screen gutters, never past the ring screen's own 358pt frame. Nothing is drawn until that box is measured, so a ring is never guessed too big for a short phone.

The patch floats. It drifts 6pt up and down every 5 seconds — the unlock celebration's idle float, one shared definition (mobile/src/components/celebration/idleFloat.ts, used at HuntHero.tsx:67 and by both celebration stages). Only while Home is the screen you see; under another screen, or with reduced motion, it holds still. There is no progress arc and no family atmosphere on this hero: those belong to the campaign pages.

The glass is the app's one glass. The menu and bell are IconButton variant="glass", which draws on Scout.GlassSurface: clear Liquid Glass on iOS 26+, a light blur with a rim on older iOS, a translucent stand-in on Android, solid under Reduce Transparency (see design-system). The bar itself is transparent, like the ring screens' chrome.

Home's side effects are shared, not copied. The intro beat, the throttled syncNow() on focus, the 10-second unlock check, the permission prompt, the bell refresh and the app-load-complete signal all live in useHomeLifecycle (mobile/src/components/home-v3/useHomeLifecycle.ts:37). Both Homes call it. The new Home's first paint waits on content and the location fix only; it no longer fetches achievements (2026-10-09).

Loading uses the house page loader: NewHomeSkeleton (NewHomeSkeleton.tsx:22: a hero block at its share of the screen, the button row, four doors, in the screen's own slots) crossfades into the screen. The top bar is not part of either: it is drawn once over both, outside the loader, because Liquid Glass under the crossfade's animated opacity draws plain until something lays it out again (seen on a 17 Pro, 2026-10-08). The bell is there while loading too. Which hero you get is only known once content lands, so the skeleton's hero block serves both. A failed first content load with no cache shows the shared HomeErrorState ("Unable to load content / Try Again").

Data model

No new tables. It reads the synced catalog (patches, collections, campaigns, patchCollections, patchTypes), the user's collected set, and AppConfig.placeModeRadiusMiles / cityChallengeRadiusMiles.

API surface

No new endpoint.

Key files

Configuration and flags

Edge cases and known limits

What this feature does NOT do

Tests that cover it

Open questions