Skip to content

Landing Target Tiles — Design (replaces the free-text resolver)

Date: 2026-07-20 Ticket: PHON-170 (Therapy Pack MVP) Status: approved-in-conversation, pending spec review

Goal

Replace the front-page free-text target box with a grid of curated, one-click target tiles. Deleting the "command" resolver removes three real faults the free-text box created and simplifies the landing to an outcome picker.

Problem (why the text box goes)

The free-text TargetBox + resolveTarget resolver has three faults:

  1. Opacity — a resolved target shows a bare label ("Velar fronting") and never states what it is (which phones, process vs contrast, position). The clinician can't tell what they'll get.
  2. Inconsistency — the resolver models "fronting" as a /k,ɡ/ process, but the "k vs t (fronting)" prebuilt pack is a /k/ vs /t/ contrast. Same clinical word, different target depending on entry point.
  3. Discoverability — the accepted vocabulary is a hidden magic-word list; the placeholder shows three examples and there's no way to see the real set.

A curated tile grid dissolves all three: every target is a labeled, described tile with exactly one meaning, and the full set is visible.

Design

Landing composition (WelcomeView)

Unchanged: hero headline + subline, "Open My Materials" (shown when the library is non-empty), the trust line, and the sidebar-tools escape hatch.

Removed: the TargetBox input and the separate "Popular materials" gallery section — both replaced by the target tile grid as the primary surface.

Target tile grid

A responsive grid (reuse PopularPacksGallery's Card + CardActionArea pattern) of six tiles:

  • Five featured target tiles, demand-ranked (spec §2: /r/ dominates, then /s/, minimal pairs, stopping, vocalic /r/):
  • Initial /ɹ/ (initial-r)
  • Final /s/ (final-s)
  • k vs t (fronting) (k-vs-t)
  • Stopping (stopping)
  • Vocalic /ɹ/ (vocalic-r)

Each tile: title + one-line description (already on PrebuiltPack). Click → the existing seed path (seedPack(target)createSeededPack → open editor), identical to today's PopularPacksGallery.onPick.

  • One "More targets…" tile → opens a More Targets menu (MUI Dialog):
  • the remaining prebuilt pack(s) — currently Gliding of liquids (gliding) — as clickable rows (same seed-and-open action);
  • a placeholder region for future community / sponsored packs (not built now — a commented anchor + a short "More coming soon" caption is enough);
  • a divider, then Start blanknewPack() + open the editor empty, so the clinician builds from scratch via the tools ("Add from …" section buttons). This folds the build-your-own escape hatch into the grid.

Build the menu as a filterable list of pack rows (a single array mapped to rows), so a future incremental search field can filter the rows as the user types — progressively hiding non-matching packs — without restructuring. The search field itself is out of scope now (see below); the row-list shape is the only requirement it imposes today. "Start blank" stays pinned below the (future-filterable) pack list, unaffected by any filter.

Data model

Add a featured: boolean field to PrebuiltPack (and set it on the five featured packs; gliding stays featured: false). The grid renders PREBUILT_PACKS.filter(p => p.featured); the More menu renders PREBUILT_PACKS.filter(p => !p.featured). Display order follows array order — reorder PREBUILT_PACKS so the five featured come first in demand rank.

Deletions

TargetBox.tsx (+ test), lib/resolver/resolveTarget.ts (+ test), lib/resolver/resolverVocab.ts (+ test), and WelcomeView's use of describeTarget. These are used only by the landing box (verified: no other importers). PhonemePickerDialog is shared by six tools — keep it.

Seeding flow (unchanged)

Tiles and menu rows both call the same handler WelcomeView already has: seedPack(target)usePackStore.createSeededPack(target, seeded, title)onSelectTool('editor'), with the existing seeding/seedError states and target_resolved / pack_seeded analytics. "Start blank" calls usePackStore.newPack()onSelectTool('editor') (no seed).

Out of scope

  • Actual community/sponsored pack content or a submission pipeline (just the menu anchor + caption).
  • Incremental text filtering in the More Targets menu (progressively hiding non-matching packs as you type). Anticipated; the menu is built as a filterable row list so it can be added later without rework, but the search field is not built now — it only earns its place once the pack count outgrows a short list.
  • Any change to the seeder, the editor, or the export renderer.
  • Curated per-pack word overrides (still deferred).

Testing

  • WelcomeView: renders five featured tiles; a tile click seeds and opens the editor (existing assertion, retargeted from the gallery); "More targets…" opens the menu; a menu pack row seeds+opens; "Start blank" opens an empty editor without seeding; no free-text textbox is present.
  • prebuiltPacks: exactly five featured packs; the featured set is the demand-ranked five in order.
  • Delete TargetBox / resolver tests with their sources.

Files

  • Modify: src/components/WelcomeView.tsx, src/components/WelcomeView.test.tsx, src/lib/packs/prebuiltPacks.ts (+ test), src/components/pack/PopularPacksGallery.tsx (evolve into the featured grid, or replace with a new TargetTiles + MoreTargetsMenu).
  • Create: src/components/pack/MoreTargetsMenu.tsx (+ test).
  • Delete: src/components/pack/TargetBox.tsx (+ test), src/lib/resolver/* (+ tests).