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:
- 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.
- 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. - 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 blank →
newPack()+ 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 fivefeaturedpacks; 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 newTargetTiles+MoreTargetsMenu). - Create:
src/components/pack/MoreTargetsMenu.tsx(+ test). - Delete:
src/components/pack/TargetBox.tsx(+ test),src/lib/resolver/*(+ tests).