moving
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled

This commit is contained in:
Oleg Maslov
2026-09-02 10:10:29 +02:00
commit 0c3e2ead3b
3841 changed files with 970576 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
# Path-to-9 execution · PHASE D — the motion system (Pillar 1) + home scroll-reveal
### Contract: docs/ux-refactor/path-to-9-2026-07-07.md v3 §Pillar 1 (5/5 endorsed, incl. the
### PATH-2 conditions: default route tier + hero morphs, focus/AT spec IN the component,
### interruptibility as acceptance criteria, commissioned waggle-settle prototype-first).
### The unanimous R19 #1 gap. Highest regression risk → scoped, feature-flagged, staged.
### All motion uses lib/motion/tokens.ts. Both themes. Reduced-motion per REDUCED map.
Recon (verified): router = react-router `<Routes>` in App.tsx; the layout route `/`
= AppShell whose single `<Outlet/>` (AppShell.tsx:449) renders the active route inside
`<main class="relative z-10 flex-1 overflow-hidden">`. `location`, `useNavigate`,
`AnimatePresence` already imported. ChatHost keep-alive portal is SEPARATE from the
Outlet (must not be wrapped — it protects in-flight SSE). Phase-0 spring family +
`--mo-*` tokens + REDUCED map exist. Hover tier = the shipped `hive-interactive`-style
classes on cards (Wave T/U/V). AmbientHiveGlow shipped Phase C (home breath).
## STAGE 1 (parallel; the two heavy motion lanes are independent)
### Lane RT — route-transition system (Pillar 1.1; PATH-2 design blocking)
Files: NEW `components/os/RouteTransition.tsx` (+ test), `components/os/AppShell.tsx`
(wrap the Outlet only), `lib/feature-flags.ts` or a local flag (verify the flag pattern),
tests.
1. **DEFAULT tier — fade-through crossfade + persistent chrome** on ALL top-level route
changes: wrap `<Outlet/>` in `<AnimatePresence mode="popLayout">` keyed by a ROUTE-GROUP
key (NOT the full pathname — a workspace tab change within /workspaces/:id must not
crossfade the whole surface; derive the key from the top segment: home/workspaces/
memory/agents/marketplace/settings/…). Enter/exit = opacity fade-through (150200ms,
`--mo-base` + `EASE_OUT`); the sidebar + StatusBar are OUTSIDE the animated subtree
(persistent chrome — they never fade). NOT a global router rewrite.
2. **Interruptibility + input-primacy** (PATH-2 design blocking — ACCEPTANCE, tested):
a route change mid-transition redirects immediately (AnimatePresence popLayout allows
the new child in without waiting for exit); navigation/input NEVER waits on an exit
animation. Add a test: fire two navigations in quick succession → the final route wins,
no lock. Keep `mode="popLayout"` (not "wait") precisely so exits don't block enters.
3. **Focus + assistive-tech spec IN the component** (PATH-2 a11y blocking): on route
commit, move focus to the destination surface's primary heading / `<main>` landmark
(focus a `tabIndex={-1}` ref); set the EXITING subtree `inert`+`aria-hidden` for its
exit duration (focus/SR cursor can never land in it); announce the route via a polite
live region (route label). Ship these INSIDE RouteTransition, not as a follow-up.
4. **Reduced-motion**: crossfade → instant swap (REDUCED.routeTransition = 'crossfade-only'
means: under reduce, no opacity animation — instant), focus + announce still fire.
5. **Feature-flag** the whole thing (default ON in dev, but a kill switch) so a regression
is one flag flip. Verify the ChatHost keep-alive still works (SSE survives a route
change — do not wrap ChatHost).
### Lane HM — hero shared-element morphs (Pillar 1.1 hero cases)
Files: `apps/AllWorkspacesApp.tsx` + the workspace route/surface (`layoutId` on the card→
surface), `apps/memory/*` (Trust↔Memories tab morph), tests. Depends on Lane RT's
RouteTransition existing (Stage 1 both start; HM reads RT's exports — if RT isn't merged
yet, HM implements the layoutId pairs and notes the integration point).
1. **card→workspace-open**: the workspace card's hex avatar + name share a `layoutId` with
the destination workspace header, so opening a card GROWS it into the surface (framer
`layoutId` + `LayoutGroup`). Scope to this ONE pair; fall back to the default crossfade
if the destination header isn't mounted.
2. **Trust↔Memories tab morph**: the shared hero/container morphs between the two memory
tabs (layout animation on the tab panel), not a hard cut.
3. Interruptibility + reduced-motion (instant) as Lane RT item 2/4. Both morphs motion-safe.
## STAGE 2 (parallel; after Stage 1)
### Lane HV — hover amplitude: "honey responds to touch" (Pillar 1.2; brand HIGH ×3 rounds)
Files: the shared hover-tier class/util (grep where cards define hover — likely inline
Tailwind on AllWorkspacesApp/SuggestedAgentCards/ExtensionCard; if there's a shared
`hive-interactive` class in index.css, edit there; else create ONE and adopt), tests.
1. Bump the hover tier amplitude to a felt "honey blooms under the cursor": on hover/
focus-visible → lift (translate-y 2→4px), shadow step, honey border-warm, AND a soft
honey glow bloom (box-shadow with `--shadow-honey`/`--honey-glow`), 120160ms
`--mo-fast` + spring feel. ONE implementation adopted by workspace cards, agent cards,
marketplace rows, provider tiles. Reduced-motion: keep color/shadow, drop translate.
2. Keep the brand judge's WIN ("respectful, not gratuitous") — bloom is subtle, not neon.
Light theme: verify the glow reads on ivory (Phase-A light --honey-glow / deeper honey).
### Lane SR — home day-story scroll-reveal (Pillar 1.1 entrance; R20 design HIGH)
Files: `apps/HomeCockpit.tsx` (+ the home section components), tests.
1. The home "day story" (I REMEMBER → START HERE → memory-review → WHILE YOU SLEPT →
pick-up cards) reveals on scroll: each section rises 8px + fades in as it enters the
viewport (IntersectionObserver + the `card-enter` / STAGGER grammar), once per section
per visit. So the scripted scroll reads as designed motion, not a static page.
Reduced-motion: all visible immediately, no rise/fade. Do not re-trigger on scroll-up.
## STAGE 3 (the signature gesture — prototype-first, PATH-2 brand blocking)
### Lane WS — the waggle-settle, commissioned + prototyped STANDALONE
Files: NEW `components/os/warm/WaggleSettle.tsx` (+ test) + a `/motion-spec` section
demonstrating it on exactly ONE moment (memory saved). Do NOT propagate to other moments
in this phase — the prototype is judged first (a mini standalone review), THEN rolled out
per the Phase-0 SIGNATURE frequency taxonomy in a later step.
1. A recognizably waggle-derived micro-choreography: a brief directional waggle-run
(the bee's figure-eight dance DNA — a small side-to-side + forward settle) → settle,
~300400ms (DUR.settle, SPRING.expressive), honey. Reduced-motion: instant state +
color pulse (no path motion). It must read as "the waggle," not a generic scale-pop.
2. Wire it to ONE moment only: the memory-saved confirmation (find the save-memory
success path — grep). Render it there behind the SIGNATURE.full taxonomy gate
(per-session cooldown). Everything else waits for the standalone judge verdict.
## VERIFY STAGE (adversarial)
- **V1-motion-system**: RouteTransition — is the crossfade interruptible (the double-nav
test), is the focus/AT spec implemented (focus moves to heading, exiting tree inert,
route announced), does reduced-motion degrade to instant, does ChatHost SSE survive a
route change? Hero morphs — do the layoutId pairs animate (code-read + the 12fps
capture if available)?
- **V2-hover-scroll**: hover amplitude felt (inspect the class), light-theme glow reads,
reduced-motion drops translate; scroll-reveal fires once per section, reduced-motion off.
- **V3-a11y-regression**: the highest risk — a keyboard-only pass through 3 route changes
(focus lands on the destination heading each time, no focus trapped in an exiting tree,
route announced); reduced-motion Playwright pass asserting no route-transition opacity
animation under reduce.
## Orchestrator after verify
tsc web + full vitest + all ux-gates (contrast/text-guard/warm/runtime) + reduced-motion
gate + browser smoke (route changes crossfade, one card→workspace morph, hover bloom) →
commit → **standalone waggle-settle mini-judge** (is it "the waggle"? kitsch check) →
if approved, roll out per taxonomy → kit-v7 capture → **R22 judge (9-ATTEMPT: min ≥ 9.0)**.
If R22 min < 9 but ≥ 8.5, one convergent-fix round; if it plateaus, stop + re-analyze.