# UI Micro-Interactions Component Map (MI6) This document maps StellaOps UI components to their interaction types and motion token usage. Components must use tokens from the catalog (`tokens/motion.scss`, `motion-tokens.ts`) rather than bespoke values. ## Token Catalog Reference | Token | CSS Variable | Duration | Use Case | | --- | --- | --- | --- | | durationXs | --motion-duration-xs | 80ms | Focus rings, instant feedback | | durationSm | --motion-duration-sm | 140ms | Hover states, button presses | | durationMd | --motion-duration-md | 200ms | Modal open/close, panel slide | | durationLg | --motion-duration-lg | 260ms | Page transitions, accordions | | durationXl | --motion-duration-xl | 320ms | Complex sequences, onboarding | | easeStandard | --motion-ease-standard | cubic-bezier(0.2,0,0,1) | Default for all transitions | | easeEntrance | --motion-ease-entrance | cubic-bezier(0.18,0.89,0.32,1) | Elements appearing | | easeExit | --motion-ease-exit | cubic-bezier(0.36,0,-0.56,-0.56) | Elements leaving | | easeBounce | --motion-ease-bounce | cubic-bezier(0.34,1.56,0.64,1) | Playful feedback only | ## Component Mapping | Component | Interaction Type | Tokens Used | Reduced-Motion Behavior | | --- | --- | --- | --- | | Button (primary) | Hover lift, press scale | durationSm, easeStandard, scaleSm | No transform, instant state change | | Button (secondary) | Hover border, press | durationXs, easeStandard | Instant state change | | Modal/Dialog | Fade + slide up | durationMd, easeEntrance/Exit, translateMd | Instant show/hide | | Dropdown/Menu | Fade + scale | durationSm, easeStandard, scaleSm | Instant show/hide | | Toast/Snackbar | Slide in, auto-dismiss | durationMd, easeEntrance, translateLg | Instant show/hide | | Accordion | Height expand | durationMd, easeStandard | Instant toggle | | Tabs | Indicator slide | durationSm, easeStandard | Instant indicator | | Progress bar | Width fill | durationMd, easeStandard | No animation, instant fill | | Spinner/Loader | Rotate animation | N/A (CSS keyframe) | Static icon or hidden | | Skeleton | Shimmer pulse | durationXl, easeStandard | Static skeleton, no shimmer | | Badge (status) | Scale pop on change | durationXs, easeBounce, scaleSm | No scale, instant | | Focus ring | Fade in | durationXs, easeStandard | Always visible, no fade | | Tooltip | Fade + offset | durationSm, easeEntrance, translateSm | Instant show/hide | | Banner (info) | Slide down | durationMd, easeEntrance, translateMd | Instant show/hide | | Error state | Shake animation | durationSm, easeStandard | No shake, border only | ## Perf Budget Compliance (MI5) | Metric | Budget | Measurement | | --- | --- | --- | | Interaction response | <= 100ms | Time to visual feedback | | Animation frame (avg) | <= 16ms | Chrome DevTools Performance | | Animation frame (p95) | <= 50ms | Chrome DevTools Performance | | Layout shift | <= 0.05 CLS | Lighthouse CI | | LCP placeholder | Show within 400ms | Lighthouse CI | ## Validation Rules 1. **Lint rule**: ESLint/Stylelint blocks non-catalog easing values in `.scss` and `.ts` files 2. **Storybook check**: All component stories must demonstrate reduced-motion variant 3. **Playwright check**: Snapshot tests run with `--disable-animations` and reduced-motion emulation 4. **CI gate**: Perf budget failures block merge --- ## TTFS Component Interactions > Per advisory §15: Component-to-interaction mapping for Time-to-First-Signal. ### FirstSignalCard Component **Location:** `src/app/features/runs/components/first-signal-card/` | Interaction | Trigger | Duration | Easing | Token | |-------------|---------|----------|--------|-------| | Skeleton shimmer | Initial load | 2s loop | linear | Custom keyframe | | Skeleton → Content | Signal loaded | 200ms | easeEntrance | `durationMd` | | Badge appear | Kind change | 140ms | easeEntrance | `durationSm` | | Progress update | Phase change | 140ms | easeStandard | `durationSm` | | Button hover | Mouse enter | 80ms | easeStandard | `durationXs` | | Button press | Click | 80ms | easeExit | `durationXs` | | Error shake | Load error | 260ms | easeStandard | `durationLg` | **Telemetry Events:** | Event | Trigger | Payload | |-------|---------|---------| | `ttfs_start` | Component mount | `{ runId, surface, t }` | | `ttfs_signal_rendered` | Signal displayed | `{ runId, surface, cacheHit, source, kind, ttfsMs }` | | `ui.click.action` | Action button click | `{ runId, actionType, target }` | | `ui.retry` | Retry button click | `{ runId, errorCode }` | **Accessibility:** | Requirement | Implementation | |-------------|----------------| | Focus visible | `:focus-visible` outline on buttons | | Screen reader | `aria-live="polite"` on content area | | Loading state | `aria-busy="true"` on card | | Status | `role="status"` on badge | | Keyboard | Tab navigation, Enter/Space activation | | Reduced motion | Disable shimmer, use instant transitions | ### EvidencePanel Component **Location:** `src/app/features/evidence/evidence-panel.component.ts` | Interaction | Trigger | Duration | Easing | Token | |-------------|---------|----------|--------|-------| | Tab switch | Tab click | 200ms | easeStandard | `durationMd` | | Panel expand | Accordion open | 260ms | easeEntrance | `durationLg` | | Panel collapse | Accordion close | 200ms | easeExit | `durationMd` | | Copy success | Copy button | 140ms | easeEntrance | `durationSm` | | Copy tooltip | After copy | 2s visible | — | — | | Export progress | Export start | Indeterminate | linear | Spinner | **Telemetry Events:** | Event | Trigger | Payload | |-------|---------|---------| | `finding_open` | Panel mount | `{ findingId, entryPoint, t }` | | `proof_rendered` | Proof visible | `{ findingId, proofKind, source, t }` | | `ui.copy.verify_command` | Copy verify cmd | `{ type: 'cosign'|'rekor'|'bundle' }` | | `evidence.export` | Export complete | `{ findingId, fileSize }` | ### ProofSpine Component **Location:** `src/app/features/evidence/components/proof-spine/` | Interaction | Trigger | Duration | Easing | Token | |-------------|---------|----------|--------|-------| | Hash truncation expand | Hover/focus | 140ms | easeStandard | `durationSm` | | Copy single | Copy button | 80ms | easeExit | `durationXs` | | Copy all | Copy all button | 140ms | easeEntrance | `durationSm` | | Status badge | Load | 200ms | easeEntrance | `durationMd` | --- ## TTFS Telemetry Event Catalog ### Core Events | Event | Category | Sampling | Always Sample | |-------|----------|----------|---------------| | `ttfs_start` | ttfs | Per config | No | | `ttfs_signal_rendered` | ttfs | Per config | No | | `ttfs_timeout` | ttfs | — | Yes | | `ttfs_error` | ttfs | — | Yes | ### TTE Events | Event | Category | Sampling | Always Sample | |-------|----------|----------|---------------| | `finding_open` | tte | Per config | No | | `proof_rendered` | tte | Per config | No | ### UX Events | Event | Category | Sampling | Always Sample | |-------|----------|----------|---------------| | `ux.bounce` | ui | — | Yes | | `ux.non_bounce` | ui | Per config | No | | `ux.open_to_action` | ui | Per config | No | | `ui.copy.*` | ui | Per config | No | | `ui.click.*` | ui | Per config | No | | `evidence.export` | ui | Per config | No | ### Sampling Configuration | Environment | TTFS Rate | TTE Rate | UI Rate | |-------------|-----------|----------|---------| | Development | 100% | 100% | 100% | | Staging | 100% | 100% | 100% | | Production | ≥25% | 50% | 25% | --- ## TTFS State Machine ``` FirstSignalCard: idle → loading → loaded ↘ unavailable ↘ error → (retry) → loading EvidencePanel: idle → loading → loaded ↘ partial (some proofs failed) ↘ error ``` --- ## File Locations (TTFS) | Deliverable | Path | |-------------|------| | FirstSignalCard | `src/Web/StellaOps.Web/src/app/features/runs/components/first-signal-card/` | | FirstSignalStore | `src/Web/StellaOps.Web/src/app/features/runs/stores/first-signal.store.ts` | | EvidencePanel | `src/Web/StellaOps.Web/src/app/features/evidence/evidence-panel.component.ts` | | ProofSpine | `src/Web/StellaOps.Web/src/app/features/evidence/components/proof-spine/` | | TTFS Telemetry | `src/Web/StellaOps.Web/src/app/core/telemetry/ttfs-telemetry.service.ts` | | Sampling Config | `src/Web/StellaOps.Web/src/app/core/telemetry/telemetry-config.ts` | | i18n Keys | `src/Web/StellaOps.Web/src/assets/i18n/en.json` | | Test Fixtures | `tests/fixtures/ttfs/ttfs-fixtures.ts` | | E2E Tests | `src/Web/StellaOps.Web/tests/e2e/micro-interactions.spec.ts` | --- ## Evidence - Token catalog: `src/Web/StellaOps.Web/src/styles/tokens/_motion.scss` - TypeScript tokens: `src/Web/StellaOps.Web/src/app/styles/motion-tokens.ts` - Storybook stories: `src/Web/StellaOps.Web/src/stories/motion-tokens.stories.ts` - TTFS Architecture: `docs/modules/telemetry/ttfs-architecture.md` - Advisory: `docs/product-advisories/14-Dec-2025 - UX and Time-to-Evidence Technical Reference.md` --- ## References - Sprint 0338: TTFS Foundation - Sprint 0339: First Signal API - Sprint 0340: FirstSignalCard UI - Sprint 0341: TTFS Enhancements