From 97cb530a86ead9123e9453d23f223750de418185 Mon Sep 17 00:00:00 2001 From: rUv Date: Sun, 23 Aug 2026 19:40:56 -0400 Subject: [PATCH] feat(mobile): adopt NLOS instrument interface --- .github/workflows/consumer-nlos-ci.yml | 154 +++ ...-cognitum-inspired-mobile-instrument-ui.md | 512 ++++++++ .../consumer-nlos-mobile-ui/README.md | 15 + .../overview-390x844.png | Bin 0 -> 81551 bytes .../consumer-nlos-mobile-ui/setup-390x844.png | Bin 0 -> 85245 bytes .../synthetic-390x844.png | Bin 0 -> 53743 bytes ui/ios-nlos/App/ContentView.swift | 1047 +++++++++++++---- ui/ios-nlos/App/TrackCanvas.swift | 163 ++- ui/mobile/.gitignore | 3 + ui/mobile/e2e/nlos_mobile_ui.yaml | 39 + ui/mobile/e2e/web/nlos.mobile.spec.ts | 109 ++ ui/mobile/e2e/web/serve.mjs | 49 + ui/mobile/eslint.config.js | 11 +- ui/mobile/jest.config.js | 7 +- ui/mobile/package-lock.json | 64 + ui/mobile/package.json | 6 +- ui/mobile/playwright.config.ts | 38 + .../src/__tests__/screens/NLOSScreen.test.tsx | 141 ++- ui/mobile/src/components/InstrumentPanel.tsx | 155 +++ .../src/screens/NLOSScreen/BetaSetupCard.tsx | 146 ++- .../NLOSScreen/HiddenTargetVisualization.tsx | 64 +- .../screens/NLOSScreen/ProvenancePanel.tsx | 134 ++- ui/mobile/src/screens/NLOSScreen/index.tsx | 550 +++++++-- 23 files changed, 2966 insertions(+), 441 deletions(-) create mode 100644 docs/adr/ADR-342-cognitum-inspired-mobile-instrument-ui.md create mode 100644 docs/screenshots/consumer-nlos-mobile-ui/README.md create mode 100644 docs/screenshots/consumer-nlos-mobile-ui/overview-390x844.png create mode 100644 docs/screenshots/consumer-nlos-mobile-ui/setup-390x844.png create mode 100644 docs/screenshots/consumer-nlos-mobile-ui/synthetic-390x844.png create mode 100644 ui/mobile/e2e/nlos_mobile_ui.yaml create mode 100644 ui/mobile/e2e/web/nlos.mobile.spec.ts create mode 100644 ui/mobile/e2e/web/serve.mjs create mode 100644 ui/mobile/playwright.config.ts create mode 100644 ui/mobile/src/components/InstrumentPanel.tsx diff --git a/.github/workflows/consumer-nlos-ci.yml b/.github/workflows/consumer-nlos-ci.yml index 43d36e80..63b5506e 100644 --- a/.github/workflows/consumer-nlos-ci.yml +++ b/.github/workflows/consumer-nlos-ci.yml @@ -11,8 +11,10 @@ on: - 'docs/adr/ADR-32[8-9]*' - 'docs/adr/ADR-33[0-1]*' - 'docs/adr/ADR-341-consumer-nlos-beta-tester-delivery-and-diagnostics.md' + - 'docs/adr/ADR-342-cognitum-inspired-mobile-instrument-ui.md' - 'docs/research/consumer-nlos-acceptance-protocol.md' - 'docs/research/consumer-nlos-beta-test-protocol.md' + - 'docs/screenshots/consumer-nlos-mobile-ui/**' - 'docs/schemas/ruview-nlos-*.schema.json' - 'docs/schemas/ruview-ios-visible-depth-diagnostic-v1.schema.json' - 'docs/security/consumer-nlos-threat-model.md' @@ -27,6 +29,8 @@ on: - 'ui/mobile/**' - 'harness/ruview/**' - 'docs/**consumer-nlos*' + - 'docs/adr/ADR-342-cognitum-inspired-mobile-instrument-ui.md' + - 'docs/screenshots/consumer-nlos-mobile-ui/**' - 'docs/schemas/ruview-ios-visible-depth-diagnostic-v1.schema.json' - '.github/workflows/consumer-nlos-ci.yml' - 'v2/Cargo.toml' @@ -118,6 +122,20 @@ jobs: - run: npm test -- --runInBand - run: npx tsc --noEmit - run: npm run lint + - name: Install pinned Playwright Chromium + run: ./node_modules/.bin/playwright install --with-deps chromium + - name: Run production browser E2E and reproduce mobile screenshots + run: npm run e2e:web + - name: Upload browser E2E review evidence + if: ${{ !cancelled() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: consumer-nlos-mobile-ui-browser-${{ github.sha }} + path: | + docs/screenshots/consumer-nlos-mobile-ui + ui/mobile/test-results/playwright + if-no-files-found: warn + retention-days: 14 - name: Export browser bundle run: npx expo export --platform web - name: Export Expo iOS bundle @@ -136,6 +154,142 @@ jobs: console.log(JSON.stringify(report.metadata?.vulnerabilities ?? {}, null, 2)); JS + mobile-ui-contract: + name: Mobile UI ADR, E2E, and screenshot contract + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + + - name: Validate UI-only architecture and deterministic review evidence + shell: bash + run: | + set -euo pipefail + python - <<'PY' + import re + import struct + from pathlib import Path + + adr_path = Path( + "docs/adr/ADR-342-cognitum-inspired-mobile-instrument-ui.md" + ) + flow_path = Path("ui/mobile/e2e/nlos_mobile_ui.yaml") + screenshot_dir = Path("docs/screenshots/consumer-nlos-mobile-ui") + + adr = adr_path.read_text(encoding="utf-8") + required_sections = ( + "## Context", + "## Specification", + "## Pseudocode and state transitions", + "## Architecture", + "## Decision", + "## Alternatives with quantified tradeoffs", + "## Accessibility", + "## Security and privacy", + "## Performance budgets", + "## Refinement and failure handling", + "## Requirement to evidence mapping", + "## Rollout and rollback", + "## Acceptance test", + ) + for section in required_sections: + assert section in adr, f"missing ADR section: {section}" + + required_adr_contract = ( + "UI-only", + "feat/consumer-nlos-ruview", + "Cognitum Explain", + "No Cognitum name, logo, wordmark", + "SYNTHETIC", + "LIVE VERIFIED", + "LIVE UNVERIFIED", + "STALE", + "DISCONNECTED", + "390 by 844", + "44 by 44 points", + "under 1.5 seconds", + "under 100 milliseconds", + "zero runtime dependency", + "physical iPhone validation pending", + ) + for phrase in required_adr_contract: + assert phrase in adr, f"missing mobile UI contract: {phrase}" + + flow = flow_path.read_text(encoding="utf-8") + required_flow_contract = ( + "appId:", + "---", + "launchApp:", + "tapOn:", + "assertVisible:", + "nlos-evidence-state", + "nlos-synthetic-watermark", + "nlos-beta-setup", + ) + for token in required_flow_contract: + assert token in flow, f"missing Maestro UI contract token: {token}" + + screen_sources = "\n".join( + path.read_text(encoding="utf-8") + for path in sorted(Path("ui/mobile/src/screens/NLOSScreen").glob("*.tsx")) + ) + for test_id in ( + "nlos-evidence-state", + "nlos-synthetic-watermark", + "nlos-beta-setup", + ): + assert test_id in screen_sources, f"missing screen contract: {test_id}" + for state in ( + "SYNTHETIC", + "LIVE VERIFIED", + "LIVE UNVERIFIED", + "STALE", + "DISCONNECTED", + ): + assert state in screen_sources, f"missing evidence state: {state}" + + state_type = re.search( + r"export type NlosEvidenceState\s*=\s*(.*?);", + screen_sources, + re.DOTALL, + ) + assert state_type, "missing NlosEvidenceState type contract" + actual_states = set(re.findall(r"'([^']+)'", state_type.group(1))) + expected_states = { + "SYNTHETIC", + "LIVE VERIFIED", + "LIVE UNVERIFIED", + "STALE", + "DISCONNECTED", + } + assert actual_states == expected_states, ( + f"evidence state taxonomy drift: {sorted(actual_states)}" + ) + + def png_dimensions(path): + data = path.read_bytes() + assert data.startswith(b"\x89PNG\r\n\x1a\n"), f"not a PNG: {path}" + assert data[12:16] == b"IHDR", f"missing PNG IHDR: {path}" + return struct.unpack(">II", data[16:24]) + + expected_screenshots = ( + "overview-390x844.png", + "synthetic-390x844.png", + "setup-390x844.png", + ) + for name in expected_screenshots: + path = screenshot_dir / name + assert path.is_file(), f"missing screenshot baseline: {path}" + assert png_dimensions(path) == (390, 844), ( + f"wrong screenshot dimensions for {path}: {png_dimensions(path)}" + ) + + print( + "Validated ADR 342, Maestro UI contract, five evidence states, " + "and three 390x844 PNG baselines" + ) + PY + native-ios: name: Native Swift, simulator, and unsigned archive dry gate runs-on: macos-26 diff --git a/docs/adr/ADR-342-cognitum-inspired-mobile-instrument-ui.md b/docs/adr/ADR-342-cognitum-inspired-mobile-instrument-ui.md new file mode 100644 index 00000000..51636d8d --- /dev/null +++ b/docs/adr/ADR-342-cognitum-inspired-mobile-instrument-ui.md @@ -0,0 +1,512 @@ +# ADR-342: Cognitum-inspired mobile instrument UI for RuView NLOS + +| Field | Decision | +|---|---| +| **Status** | Proposed; software implementation and deterministic review evidence are part of a stacked UI-only pull request, while physical-device validation remains operator-gated | +| **Date** | 2026-08-23 | +| **Owners** | RuView Labs mobile, iOS, design, accessibility, privacy, security, and research maintainers | +| **Scope** | Presentation, responsive layout, evidence-state projection, accessibility semantics, mobile end-to-end review flow, and screenshot baselines for the Expo and native SwiftUI NLOS clients | +| **Depends on** | ADR-295, ADR-318, ADR-319, ADR-330, ADR-340, ADR-341 | +| **Stacked pull request base** | `feat/consumer-nlos-ruview`, the head branch for pull request 1687; retarget to `main` after the dependency merges | +| **Implementation boundary** | `ui/mobile` presentation and tests, `ui/ios-nlos/App` presentation, the mobile UI screenshot baselines, and the UI validation portion of `.github/workflows/consumer-nlos-ci.yml` | + +## Context + +RuView NLOS already exposes strict source provenance, frame freshness, setup, +diagnostic, and transport behavior in its Expo and native SwiftUI clients. The +mobile presentation does not yet have one coherent instrument language. Its +most important state can consequently compete with setup copy, controls, and +technical detail on a narrow phone viewport. + +The requested direction is similar to the visual language of Cognitum Explain +Studio: a near-black technical canvas, fine grid, restrained cyan and green +accents, compact monospaced labels, thin luminous outlines, and an orbital or +radar motif. This decision adopts that visual language as design provenance, +not as a product or code dependency. No Cognitum name, logo, wordmark, copy, +source code, private asset, authentication behavior, or investor-deck branding +is reused. RuView keeps its own name, logo, evidence vocabulary, information +architecture, and privacy boundary. + +The authenticated Studio route was not available to the automated cloud review +session. The initial contract is therefore derived from the product owner's +direction and the visual characteristics observable on the available hosted +Cognitum Explain reference surface. Pixel equivalence with the authenticated +Studio route is neither claimed nor required. A maintainer with authorized +Studio access can later provide an approved reference screenshot and request a +bounded visual refinement without changing the epistemic or privacy rules in +this decision. + +This is a UI-only decision. It must not change sensing, reconstruction, +filtering, transport, credential storage, permissions, diagnostic contents, +data retention, or claims. Existing source-validation and fail-closed behavior +remain authoritative. The UI projects that state; it does not invent or +upgrade it. + +## Specification + +### Outcome and actors + +The outcome is a unified mobile instrument surface that lets a tester identify +the active evidence state, understand the privacy boundary, inspect current +hidden-target hypotheses when allowed, and reach the next safe action without +reading the entire screen. + +Actors are beta testers, researchers, accessibility users, support maintainers, +design reviewers, privacy and security reviewers, and the release operator. + +### Inputs + +1. Existing validated Expo NLOS store values: frame source, freshness, stream + status, accepted tracks, credential availability, and rejection reason. +2. Existing native `AppModel` connection, capability, frame, track, and visible + depth validation state. +3. Current device safe-area insets, viewport dimensions, Dynamic Type or browser + text scaling, reduced-motion preference, and high-contrast settings. +4. Local user actions such as selecting a view, opening setup guidance, + starting synthetic replay, connecting an authenticated live source, or + forgetting a credential. + +### Outputs + +1. A narrow-screen overview with a single prominent evidence state. +2. A visual instrument region that shows only tracks already allowed by the + existing validation and freshness boundary. +3. Setup, provenance, privacy, and interpretation guidance in a stable reading + order. +4. Reviewable screenshot baselines for overview, synthetic, and setup states. +5. A production-browser Playwright end-to-end suite and a mobile Maestro flow + that verify navigation, state visibility, synthetic watermarking, setup + affordances, and the primary local action. + +### Honest evidence-state taxonomy + +The presentation exposes exactly five top-level states. These are display +projections over existing domain state and do not create a second sensing state +machine. + +| Display state | Minimum condition | Required presentation | Forbidden presentation | +|---|---|---|---| +| `SYNTHETIC` | A fresh accepted frame is explicitly sourced from synthetic replay | Persistent amber label and watermark in the instrument region | Green live treatment, verified language, or removal of the watermark | +| `LIVE VERIFIED` | A fresh accepted live frame has authenticated transport and satisfies the existing provenance and evidence gate | Green and cyan live label plus source and freshness details | Inferring verification from connection status alone | +| `LIVE UNVERIFIED` | A live transport is active or attempting to provide data, but no fresh frame satisfies the full verification gate | Amber caution label, withheld target visualization, and corrective guidance | Calling the source verified or silently substituting replay | +| `STALE` | A previously displayable frame has exceeded the existing freshness threshold | High-priority stale label, age context when available, and suppression of hidden-target geometry | Continuing to show cached targets as current | +| `DISCONNECTED` | No eligible fresh source is active and no stale frame needs a stronger warning | Neutral disconnected label and explicit connection or replay actions | Implied live availability or retained target geometry | + +Unknown, contradictory, or partially initialized input resolves to `LIVE +UNVERIFIED` only when an authenticated live attempt is active. It resolves to +`DISCONNECTED` otherwise. No unknown state may resolve to `LIVE VERIFIED`. + +### Layout and interaction requirements + +1. The primary reference viewport is 390 by 844 CSS pixels or iOS points. It + must have no horizontal document or root-scroll overflow at 100 percent text + scale. +2. The layout must remain functional at 320 points wide and with text enlarged + to 200 percent. Secondary rows may wrap vertically; essential state, privacy, + and action text may not be clipped. +3. Interactive targets have a minimum hit area of 44 by 44 points. Adjacent + targets maintain at least 8 points of separation unless their combined + control supplies equivalent accessible grouping. +4. Evidence state is encoded by text and icon or shape as well as color. Color + is never the sole differentiator. +5. The semantic reading order is identity and evidence state, instrument, + metrics, primary actions, setup, provenance, privacy, then technical detail. +6. The existing explainer and tester-feedback destinations remain visible from + setup without collecting credentials or diagnostics. +7. Motion is decorative and bounded. Reduced-motion mode removes continuous + orbit, sweep, pulse, and parallax effects without removing information. + +### Performance budgets + +1. Initial usable render is under 1.5 seconds in a production browser build on + a representative modern iPhone under the recorded test conditions. Usable + means the evidence state and primary action are visible and respond to input. +2. Local UI state interactions have p95 input-to-committed-visual latency under + 100 milliseconds over at least 30 repetitions on the same device. +3. Continuous decorative animation must not be required for state recognition. + It pauses when the app or page is inactive and honors reduced motion. +4. The redesign adds no network request, remote font, remote image, analytics + client, sensor subscription, or background timer. +5. Screenshot rendering is deterministic: fixed viewport, fixed fixtures, + reduced motion, local assets, and no dependency on a live endpoint. + +The timing budgets are targets until a physical iPhone report records device, +OS, build commit, build mode, browser, network conditioning, repetition count, +median, and p95. CI and desktop browser results are software evidence and must +not be relabeled as physical-device measurements. + +### Explicit exclusions + +This decision does not authorize or alter optical NLOS sensing, ARKit capture, +CSI ingestion, WebSocket protocol behavior, endpoint validation, token handling, +Keychain behavior, browser credential persistence, permission prompts, +diagnostic schema, upload behavior, raw-data retention, background sensing, +identity inference, health or safety use, or camera-equivalence claims. + +## Pseudocode and state transitions + +### Evidence-state projection + +```text +projectEvidenceState(domain): + if domain.freshness == stale and domain.previouslyDisplayableFrameExists: + return STALE + + if domain.freshness == fresh and domain.acceptedFrame.source == synthetic: + return SYNTHETIC + + if domain.liveAttemptActive: + if domain.freshness == fresh + and domain.acceptedFrame.source == live + and domain.transportAuthenticated + and domain.provenanceGatePassed + and domain.evidenceGatePassed: + return LIVE_VERIFIED + return LIVE_UNVERIFIED + + return DISCONNECTED +``` + +The projection consumes authoritative state without mutating it. A source +cannot become verified because a user tapped a control, because a socket is +open, or because a previous frame was verified. + +### Presentation control flow + +```text +onRender: + state = projectEvidenceState(authoritativeDomainState) + announce state when it changes, but do not repeatedly announce frame updates + render state text, redundant icon or shape, and provenance summary + + if state == SYNTHETIC: + render only accepted fresh replay tracks + render persistent SYNTHETIC watermark above the instrument + else if state == LIVE_VERIFIED: + render only accepted fresh live tracks + else: + render no hidden-target geometry + render safe recovery guidance for the current state + + preserve setup, privacy, interpretation, and feedback paths + disable decorative motion when reduced motion is requested +``` + +### Responsive layout flow + +```text +layout(viewport, textScale, safeArea): + availableWidth = viewport.width - safeArea.left - safeArea.right + apply bounded horizontal inset + place identity and evidence status before the instrument + stack metrics and actions when their measured width does not fit + allow labels to wrap; never reduce essential text below token minimum + assert rootScrollWidth <= viewport.width + assert every interactive hit rectangle >= 44 by 44 points +``` + +### Screenshot flow + +```text +captureBaseline(name, fixture): + build production web bundle + serve local immutable bundle + set viewport to 390 by 844 + enable reduced motion and deterministic fixture mode + navigate to NLOS screen + apply fixture and wait for stable UI contract marker + assert evidence-state marker and state-specific safety cues + assert root has no horizontal overflow + save PNG with expected dimensions +``` + +### Success and failure walks + +Success case: synthetic replay provides a fresh accepted frame. The projection +returns `SYNTHETIC`, the instrument shows only accepted tracks, a visible amber +label and watermark remain present, and no live wording appears. The user can +switch local views without changing provenance. All invariants hold. + +Failure case: an authenticated live frame becomes stale while targets were +visible. The next projection returns `STALE`, removes target geometry, displays +the stale warning, and offers recovery guidance. A reconnect cannot restore +`LIVE VERIFIED` until a new accepted frame passes the existing gates. All +invariants hold. + +Contradiction case: transport reports connected while the frame provenance is +missing. The projection returns `LIVE UNVERIFIED`, does not render target +geometry, and never infers verification from connection state. All invariants +hold. + +## Architecture + +### Component boundaries + +| Component | Responsibility | May change in this decision | Must not change | +|---|---|---|---| +| Expo NLOS screen and presentation components | Responsive hierarchy, tokens, evidence-state label, accessible controls, instrument composition | Yes | Store semantics, service requests, credential lifecycle | +| Native SwiftUI shell and presentation helpers | Equivalent hierarchy, tokens, state labels, Dynamic Type, reduced motion, hit targets | Yes | `AppModel`, Apple capability probe, stream guard, Keychain, diagnostics | +| Existing Expo store and hooks | Authoritative source, freshness, frame, rejection, and connection inputs | No | Any sensing or transport behavior | +| Existing native model and core packages | Authoritative connection, frame, track, diagnostic, and capability inputs | No | Any sensing, validation, persistence, or permission behavior | +| Playwright production-browser suite | Black-box responsive navigation, overflow assertions, local state actions, and screenshot reproduction | Yes | Live endpoint use, credentials, or physical-device claims | +| Maestro mobile review flow | Black-box native navigation and visible safety-contract assertions | Yes | Production state or credentials | +| Screenshot harness and baselines | Deterministic visual review evidence | Yes | Live endpoint access or physical-hardware claims | +| Consumer NLOS CI | Build, test, static UI-contract and baseline validation | UI validation only | Signing, upload, secrets, or release authority | + +### Design token contract + +The platforms implement equivalent tokens using their native systems rather +than a new shared runtime package: + +1. near-black navy canvas and elevated graphite surfaces; +2. subtle grid lines with low contrast and no information meaning; +3. cyan primary accent and green verified accent; +4. amber synthetic and unverified accent, and red stale or blocked accent; +5. thin low-opacity outlines, restrained glow, and high-contrast text; +6. editorial sans-serif hierarchy with monospaced instrument labels; and +7. orbital or radar geometry that remains decorative and can be disabled. + +Exact color values may differ enough to satisfy platform contrast and material +behavior. Semantic state, contrast, hierarchy, and spacing are the contract; +pixel identity between React Native Web and SwiftUI is not. + +### Data lifecycle and trust boundaries + +```text +existing validated domain state + -> pure evidence-state projection + -> local presentation tree + -> pixels and accessibility semantics +``` + +The redesign adds no storage and no export. Sensitive values remain in their +existing owners. Credential controls may display length-independent readiness +or masked state only; tokens never enter labels, logs, screenshots, test +fixtures, accessibility values, analytics, or error copy. Screenshot fixtures +contain synthetic, non-personal data and cannot connect to a live endpoint. + +External links remain explicit user actions handled by the operating system or +browser. Opening an explainer or feedback page cannot attach a diagnostic, +credential, scene detail, endpoint, or referrer payload created by the app. + +### Deployment and stacking + +The UI pull request is stacked on `feat/consumer-nlos-ruview` because the NLOS +clients do not yet exist on `main`. Its diff against that base contains only UI +presentation, UI tests, screenshots, this ADR, and bounded UI CI validation. +After pull request 1687 merges, maintainers retarget the UI pull request to +`main`, verify that the diff remains scoped, rerun required checks, and merge it +independently. No sensing commit is cherry-picked into the UI branch. + +## Decision + +Adopt a RuView-owned mobile instrument system inspired by the available +Cognitum Explain visual language on both Expo and native SwiftUI. Preserve one +explicit evidence-state surface, a fail-closed instrument, prominent privacy +and interpretation boundaries, and platform-native accessibility behavior. + +Use mirrored semantic tokens and state projection tests instead of sharing a +runtime UI package across TypeScript and Swift. Use deterministic Expo web +screenshots as cross-platform review references, not as proof of native pixel +output. Require an Xcode 26 build gate and a named physical-device review before +accepting native behavior or performance claims. + +## Alternatives with quantified tradeoffs + +Alternatives are scored from 1, poor, to 5, strong. Weighted score is out of +5.0. Product clarity and epistemic safety each receive 25 percent; delivery +cost, native accessibility, and long-term maintainability each receive 15, 20, +and 15 percent respectively. + +| Alternative | Clarity 25% | Epistemic safety 25% | Delivery cost 15% | Native accessibility 20% | Maintainability 15% | Weighted score | Decision | +|---|---:|---:|---:|---:|---:|---:|---| +| RuView-owned mirrored instrument system | 5 | 5 | 4 | 5 | 4 | 4.70 | Selected | +| Restyle Expo only and leave native SwiftUI unchanged | 3 | 4 | 5 | 3 | 2 | 3.40 | Rejected because two beta surfaces would disagree on the primary state and review burden would increase | +| Embed one web UI in the native app | 4 | 4 | 3 | 2 | 4 | 3.40 | Rejected because WebView startup, focus, Dynamic Type, offline behavior, and native sensor workflow integration add operational risk | +| Create a cross-platform generated token and component package now | 5 | 5 | 1 | 4 | 3 | 3.90 | Deferred because generation infrastructure is disproportionate to one screen and would expand the UI-only diff materially | +| Keep the current generic card layout | 2 | 4 | 5 | 4 | 4 | 3.65 | Rejected because the evidence state remains visually subordinate and does not meet the requested design outcome | + +The selected approach is expected to add roughly two small platform-specific +presentation implementations and one shared behavioral contract, while adding +zero runtime dependency. The cost is duplicated token maintenance. The control +is a screenshot review plus identical state names and accessibility assertions +on both platforms. + +## Accessibility + +1. Every interactive element has a descriptive label, role or trait, and a hit + target of at least 44 by 44 points. +2. Evidence state is exposed as text and an accessible value. It is not encoded + by color, glow, motion, or spatial position alone. +3. State-change announcements are debounced to meaningful transitions. Frame + rate and coordinate updates do not continuously interrupt screen readers. +4. Expo supports browser text scaling and native font scaling. SwiftUI uses + Dynamic Type and avoids fixed-height text containers for essential content. +5. At 200 percent text scale, controls may stack and cards may grow vertically; + evidence state, privacy copy, warnings, and primary actions remain complete. +6. Reduced motion removes continuous decorative animation. Increased contrast + retains distinct borders and semantic text. +7. The visual grid, glow, radar sweep, and orbital decorations are hidden from + the accessibility tree. +8. The synthetic watermark has a programmatic label in addition to its visual + rendering. + +## Security and privacy + +1. The redesign adds no permission, entitlement, endpoint, network request, + storage key, cookie, analytics event, remote asset, background mode, or data + retention path. +2. Existing credential rules remain unchanged: the Expo client holds an + ephemeral credential in memory, while the approved native client uses its + existing Keychain boundary. UI code cannot log, render, snapshot, export, or + persist the credential. +3. Screenshot and E2E fixtures are synthetic and contain no CSI, image, depth, + point-cloud, location, person, device identifier, token, endpoint, or private + diagnostic data. +4. Stale, malformed, unauthenticated, replayed, unknown, or contradictory input + fails closed through the existing validation layer and the state projection. +5. The synthetic watermark remains visible in every synthetic visualization + and captured synthetic baseline. No style token can disable it. +6. The privacy and interpretation boundary is visible without opening a menu. + Raw RF, audio, camera, depth, and transient retention remain off or absent as + defined by prior decisions. +7. External links open only after a user action and do not append app state, + credentials, diagnostics, or scene context. +8. CI uses read-only repository permission and receives no signing, App Store + Connect, endpoint, or test-user secret for the UI contract. + +## Performance budgets + +The normative performance thresholds are defined in Specification. Validation +uses three evidence classes: + +| Evidence | What it can establish | What it cannot establish | +|---|---|---| +| Deterministic CI production build | Bundle validity, type and unit tests, baseline dimensions, state-contract presence | iPhone render timing, thermal behavior, touch latency | +| Desktop browser capture at 390 by 844 | Responsive composition, overflow, fixture states, screenshot review | Mobile Safari GPU behavior or physical touch response | +| Named physical iPhone run | Mobile Safari usable-render time, local interaction p95, Dynamic Type, VoiceOver, reduced motion, safe areas | General performance across every supported device | + +No measured value is documented without its reproducer and evidence label. A +desktop or CI measurement is `MEASURED_SOFTWARE` and not a physical-device +claim. A threshold without a completed physical run remains `TARGET`. + +## Refinement and failure handling + +### Increment plan + +1. Introduce platform-local semantic colors, typography, spacing, and + instrument primitives without changing data owners. +2. Project and render the five evidence states with unit coverage for success, + stale, disconnected, contradiction, and synthetic watermark cases. +3. Recompose the Expo NLOS screen at the reference viewport and add the + production-browser Playwright suite plus Maestro mobile flow. +4. Recompose the native SwiftUI surface using equivalent semantics, Dynamic + Type, and reduced-motion behavior. +5. Capture deterministic Expo overview, synthetic, and setup baselines. +6. Run type, lint, unit, bundle, Swift package, Xcode 26, contract, accessibility, + security, and diff-scope review gates. +7. Complete the named physical iPhone gate before calling native behavior or + mobile performance validated. + +### Failure handling + +1. If state inputs conflict, use `LIVE UNVERIFIED` during an active live attempt + or `DISCONNECTED` otherwise, hide targets, and retain the rejection reason + supplied by the authoritative layer. +2. If a frame becomes stale, remove its geometry on the same committed state + transition. Reconnection alone does not restore it. +3. If decorative rendering fails, retain plain text state, controls, privacy, + and provenance. Decoration cannot block operation. +4. If the viewport overflows, stack secondary content and remove nonessential + decoration before reducing essential text or hit areas. +5. If the performance target fails, profile render count, SVG complexity, + shadow or blur cost, and animation scheduling. Reduce decorative work before + changing semantic content. +6. If a screenshot differs, the reviewer must classify it as an intended design + change, platform rendering variance, fixture drift, or regression. Baselines + are never updated solely to make CI pass. +7. If the native Xcode or physical-device gate fails, the web UI may remain + reviewable, but the pull request is not described as fully validated on iOS. +8. If authenticated Studio reference access later reveals a material mismatch, + refine nonsemantic tokens in a follow-up. Evidence and privacy behavior stay + unchanged unless a new accepted ADR explicitly changes them. + +## Requirement to evidence mapping + +| Requirement | Automated evidence | Human or physical evidence | Pass condition | +|---|---|---|---| +| UI-only scope | Pull-request diff allowlist and service or model tests | Reviewer checks no sensing, transport, permissions, persistence, or retention diff | Zero out-of-scope behavior changes | +| Cognitum-inspired, RuView-owned language | Three screenshot baselines and token review | Product reviewer compares hierarchy and general visual language | Requested characteristics present; zero Cognitum branding or private assets | +| Five honest states | Unit tests plus `nlos-evidence-state` Playwright and Maestro selectors | Reviewer verifies wording and fail-closed hierarchy | All five exact labels are representable; unknown never becomes verified | +| Synthetic safety | Unit and E2E assertions for `nlos-synthetic-watermark` | Screenshot review of synthetic baseline | Label and watermark both visible | +| 390 by 844 layout | PNG dimension contract and browser overflow assertion | Screenshot review | Exact dimensions and no horizontal overflow | +| 44 point targets | Style and interaction assertions where supported | iPhone accessibility inspector and manual target review | Every interactive hit rectangle is at least 44 by 44 points | +| Accessibility | Semantic tests, lint, and reduced-motion fixture | VoiceOver, Dynamic Type at 200 percent, contrast, and reduced-motion review | State and primary actions remain understandable and operable | +| Initial usable render under 1.5 seconds | Production build and instrumentation contract | Named modern iPhone run with recorded conditions | Measured usable render is below 1.5 seconds | +| Local interaction p95 under 100 milliseconds | Deterministic action loop instrumentation | Named iPhone run over at least 30 repetitions | Recorded p95 is below 100 milliseconds | +| Screenshot baselines | CI validates PNG format, names, dimensions, and synthetic marker contract | Reviewer approves overview, synthetic, and setup compositions | All three approved and traceable to the commit | +| No security or privacy expansion | Unit suite, dependency audit, secret scan, workflow permission review | Privacy and security diff review | No new collection, permission, storage, network, secret, or retention path | +| Native equivalence | Swift tests and Xcode 26 unsigned simulator build | Named physical iPhone inspection | Equivalent hierarchy and state semantics; no pixel-equivalence claim | + +## Rollout and rollback + +### Rollout + +1. Review the stacked diff against `feat/consumer-nlos-ruview` and confirm the + scope is limited to presentation, UI tests, screenshots, this ADR, and UI CI. +2. Require the deterministic Expo checks, screenshots, Maestro contract, Swift + tests, and Xcode 26 unsigned build to pass. +3. After pull request 1687 merges, retarget to `main`, recheck the diff, and + rerun required checks. +4. Install the resulting beta on a named supported iPhone and complete the + physical accessibility, layout, state, and performance protocol. +5. Admit beta testers only after release governance in ADR-341 remains green. + +### Rollback + +Rollback is presentation-only. Revert the mobile UI commit while preserving +the NLOS state, service, validation, credential, and diagnostic implementations +from the base feature. If only decoration is defective, disable the affected +grid, glow, orbit, or animation and retain the plain evidence state, actions, +privacy boundary, and setup path. No rollback may remove the synthetic +watermark, stale target suppression, or visible evidence label. + +## Acceptance test + +The decision is accepted only when all software gates pass and the physical +gate is either complete or explicitly recorded as pending without a claim of +full iPhone validation. + +### Deterministic software gate + +1. Build the Expo production web and iOS bundles, run type checking, lint, unit + tests, dependency audit, the production-browser Playwright suite, and the + NLOS mobile UI Maestro contract validation. +2. Render the NLOS route from a production web bundle at 390 by 844 with reduced + motion and deterministic fixtures. Assert `scrollWidth <= clientWidth`. +3. Capture and review: + `docs/screenshots/consumer-nlos-mobile-ui/overview-390x844.png`, + `docs/screenshots/consumer-nlos-mobile-ui/synthetic-390x844.png`, and + `docs/screenshots/consumer-nlos-mobile-ui/setup-390x844.png`. +4. Assert each PNG is exactly 390 by 844. Assert the synthetic baseline and E2E + flow preserve the `SYNTHETIC` label and watermark. +5. Exercise `SYNTHETIC`, `LIVE VERIFIED`, `LIVE UNVERIFIED`, `STALE`, and + `DISCONNECTED` projections. Assert stale, unverified, and disconnected states + render no hidden-target geometry. +6. Run Swift package tests and the Xcode 26 unsigned simulator build. Confirm + zero changes to core packages, sensing, transport, credentials, permissions, + diagnostic schema, or retention. + +### Physical iPhone gate + +On a named representative modern iPhone, record model, OS, commit, build mode, +browser or native client, and test conditions. Verify no overflow in portrait, +44 point hit targets, VoiceOver reading order, Dynamic Type at 200 percent, +reduced motion, all five states, synthetic watermarking, stale target removal, +initial usable render under 1.5 seconds, and local interaction p95 under 100 +milliseconds over at least 30 repetitions. + +Simulator, unsigned archive, desktop browser, or screenshot success does not +substitute for this physical gate. Until the report is attached to the pull +request or linked issue, the correct status is software-validated, with +physical iPhone validation pending. diff --git a/docs/screenshots/consumer-nlos-mobile-ui/README.md b/docs/screenshots/consumer-nlos-mobile-ui/README.md new file mode 100644 index 00000000..3aff93b2 --- /dev/null +++ b/docs/screenshots/consumer-nlos-mobile-ui/README.md @@ -0,0 +1,15 @@ +# Consumer NLOS mobile UI review captures + +These images are deterministic review captures from the production Expo web +export at a 390 by 844 viewport. The Playwright flow navigates the real mobile +application, exercises the synthetic replay control, verifies provenance and +watermark requirements, and writes the PNG files in this directory. + +The captures contain only the disconnected state, governed setup copy, and the +built in synthetic fixture. They use no live endpoint, credential, sensor data, +person data, or remote asset. They are not native iPhone screenshots, physical +LiDAR evidence, performance evidence, or proof of optical NLOS capability. + +Regenerate them from `ui/mobile` with `npm run e2e:web`. The executable design +and evidence contract is documented in +`docs/adr/ADR-342-cognitum-inspired-mobile-instrument-ui.md`. diff --git a/docs/screenshots/consumer-nlos-mobile-ui/overview-390x844.png b/docs/screenshots/consumer-nlos-mobile-ui/overview-390x844.png new file mode 100644 index 0000000000000000000000000000000000000000..7483a0050ed8b4c66abd27819fc07f7648dd87c9 GIT binary patch literal 81551 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 z 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%0A`;(zdT##C=_r$KlRV!b~0#IK(jO-|~iFlgREl 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 CESseO literal 0 HcmV?d00001 diff --git a/docs/screenshots/consumer-nlos-mobile-ui/synthetic-390x844.png b/docs/screenshots/consumer-nlos-mobile-ui/synthetic-390x844.png new file mode 100644 index 0000000000000000000000000000000000000000..277462ac86157904b79bf2e6f9671f021ecfa74a GIT binary patch literal 53743 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 z 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 Y03n40F7c?cl>h($07*qoM6N<$f>mX7DF6Tf literal 0 HcmV?d00001 diff --git a/ui/ios-nlos/App/ContentView.swift b/ui/ios-nlos/App/ContentView.swift index d25a76a5..684cf1d8 100644 --- a/ui/ios-nlos/App/ContentView.swift +++ b/ui/ios-nlos/App/ContentView.swift @@ -6,30 +6,38 @@ import SwiftUI struct ContentView: View { @ObservedObject var model: AppModel @Environment(\.scenePhase) private var scenePhase + @ScaledMetric(relativeTo: .largeTitle) private var heroFontSize: CGFloat = 42 @State private var exportConsent = false @State private var diagnosticURL: URL? @State private var exportError: String? var body: some View { NavigationStack { - ScrollView { - VStack(spacing: 18) { - onboardingCard - visibleDepthCard - Text("NLOS MONITOR") - .font(.caption.bold().monospaced()) - .foregroundStyle(.secondary) - .frame(maxWidth: .infinity, alignment: .leading) - connectionCard - statusCard - visualizationCard - capabilityCard - boundaryCard + ZStack(alignment: .top) { + RuViewTheme.background.ignoresSafeArea() + InstrumentGrid() + + ScrollView { + LazyVStack(spacing: 16) { + instrumentHeader + statusCard + visualizationCard + onboardingCard + visibleDepthCard + connectionCard + capabilityCard + boundaryCard + evidenceLegend + } + .padding(.horizontal, 16) + .padding(.top, 12) + .padding(.bottom, 36) } - .padding() + .scrollContentBackground(.hidden) } - .navigationTitle("RuView NLOS") - .background(Color(uiColor: .systemGroupedBackground)) + .toolbar(.hidden, for: .navigationBar) + .tint(RuViewTheme.cyan) + .preferredColorScheme(.dark) .onChange(of: scenePhase) { phase in if phase != .active { model.suspendForPrivacy() @@ -38,24 +46,223 @@ struct ContentView: View { } } - private var onboardingCard: some View { - card(title: "Beta tester setup") { - Label("Validate your iPhone's public ARKit LiDAR capabilities before opening the NLOS monitor.", systemImage: "iphone.gen3.radiowaves.left.and.right") - .font(.subheadline) - Text("This test measures only visible surfaces. Every result is labeled direct_depth and is never presented as around the corner evidence.") - .font(.caption.bold()) - .foregroundStyle(.orange) - Link(destination: URL(string: "https://ruview-nlos.ruv.chatgpt.site")!) { - Label("Open the visual explainer", systemImage: "safari") + private var instrumentHeader: some View { + VStack(alignment: .leading, spacing: 16) { + HStack(alignment: .center, spacing: 12) { + VStack(alignment: .leading, spacing: 7) { + Text("RUVIEW / MOBILE FIELD LAB") + .font(.caption.bold().monospaced()) + .tracking(1.6) + .foregroundStyle(RuViewTheme.muted) + HStack(spacing: 7) { + Circle() + .fill(evidenceState.color) + .frame(width: 8, height: 8) + .shadow(color: evidenceState.color.opacity(0.8), radius: 5) + Text(evidenceState.label) + .font(.caption.bold().monospaced()) + .foregroundStyle(evidenceState.color) + .lineLimit(2) + } + } + + Spacer(minLength: 4) + OrbitalSignatureView(accent: evidenceState.color) + .frame(width: 78, height: 78) + .accessibilityHidden(true) } - Link(destination: URL(string: "https://github.com/ruvnet/RuView/issues/1690")!) { - Label("Read the test guide and provide feedback", systemImage: "bubble.left.and.exclamationmark.bubble.right") + + VStack(alignment: .leading, spacing: 7) { + Text("NLOS FIELD") + .foregroundStyle(.white) + Text("MONITOR") + .foregroundStyle( + LinearGradient( + colors: [RuViewTheme.cyan, RuViewTheme.green], + startPoint: .leading, + endPoint: .trailing + ) + ) + } + .font(.system(size: heroFontSize, weight: .black, design: .rounded)) + .tracking(-1.4) + .minimumScaleFactor(0.72) + .accessibilityElement(children: .combine) + + Text("Review authenticated evidence, sensor provenance, and privacy controls in one fail closed instrument.") + .font(.subheadline) + .foregroundStyle(RuViewTheme.textSecondary) + .fixedSize(horizontal: false, vertical: true) + + HStack(spacing: 10) { + headerMetric( + eyebrow: "STREAM", + value: connectionLabel, + color: connectionColor + ) + headerMetric( + eyebrow: "EVIDENCE", + value: evidenceLabel, + color: evidenceState.color + ) + } + + HStack(spacing: 8) { + Image(systemName: "lock.shield.fill") + .foregroundStyle(RuViewTheme.green) + Text("PRIVACY GUARD ACTIVE") + .font(.caption.bold().monospaced()) + .tracking(0.7) + Spacer() + Text("FAIL CLOSED") + .font(.caption2.bold().monospaced()) + .foregroundStyle(RuViewTheme.muted) + } + .padding(.horizontal, 12) + .frame(minHeight: 44) + .background(RuViewTheme.panelStrong, in: Capsule()) + .overlay { + Capsule().stroke(RuViewTheme.green.opacity(0.3), lineWidth: 1) + } + .accessibilityElement(children: .combine) + } + .padding(.top, 4) + } + + private var statusCard: some View { + instrumentCard(eyebrow: "01 / EVIDENCE", title: "Current signal state", accent: evidenceState.color) { + HStack(alignment: .top, spacing: 12) { + ZStack { + Circle() + .fill(evidenceState.color.opacity(0.14)) + .frame(width: 48, height: 48) + Image(systemName: evidenceState.icon) + .font(.system(size: 19, weight: .semibold)) + .foregroundStyle(evidenceState.color) + } + + VStack(alignment: .leading, spacing: 4) { + Text(evidenceState.label) + .font(.headline.bold().monospaced()) + .foregroundStyle(evidenceState.color) + Text(evidenceState.detail) + .font(.caption) + .foregroundStyle(RuViewTheme.textSecondary) + .fixedSize(horizontal: false, vertical: true) + } + Spacer(minLength: 0) + } + .accessibilityElement(children: .combine) + + Text(model.statusMessage) + .font(.subheadline) + .foregroundStyle(.white) + .fixedSize(horizontal: false, vertical: true) + .padding(12) + .frame(maxWidth: .infinity, alignment: .leading) + .background(RuViewTheme.surface, in: RoundedRectangle(cornerRadius: 12)) + + if let frame = model.frame { + ViewThatFits(in: .horizontal) { + HStack(spacing: 8) { + frameBadges(frame) + } + VStack(alignment: .leading, spacing: 8) { + frameBadges(frame) + } + } + .accessibilityElement(children: .combine) + + VStack(spacing: 0) { + provenanceRow("SENSOR", frame.provenance.sensorModel) + provenanceRow("TRANSIENT", frame.provenance.transientKind.rawValue) + provenanceRow("HISTOGRAM", frame.provenance.histogramPreserved ? "preserved" : "not preserved") + provenanceRow("ALGORITHM", frame.algorithmVersion, isLast: true) + } + .background(RuViewTheme.surface, in: RoundedRectangle(cornerRadius: 12)) } } } + private var visualizationCard: some View { + instrumentCard(eyebrow: "02 / SPATIAL", title: "Hidden target hypotheses", accent: RuViewTheme.cyan) { + Text("Only validated, fresh tracks are shown. Uncertainty rings represent the reported position covariance.") + .font(.caption) + .foregroundStyle(RuViewTheme.textSecondary) + .fixedSize(horizontal: false, vertical: true) + + ZStack { + TrackCanvas(tracks: displayableTracks) + .frame(height: 310) + .privacySensitive() + + if let watermark = model.frame?.watermark { + Text(watermark) + .font(.system(size: 35, weight: .black, design: .rounded)) + .tracking(2) + .foregroundStyle(RuViewTheme.orange.opacity(0.48)) + .rotationEffect(.degrees(-18)) + .accessibilityLabel("\(watermark.capitalized) evidence watermark") + } + + if displayableTracks.isEmpty { + VStack(spacing: 8) { + Image(systemName: "scope") + .font(.title2) + Text("NO DISPLAYABLE TRACKS") + .font(.caption.bold().monospaced()) + } + .foregroundStyle(RuViewTheme.muted) + .padding(.horizontal, 14) + .padding(.vertical, 12) + .background(RuViewTheme.background.opacity(0.88), in: Capsule()) + .overlay { + Capsule().stroke(RuViewTheme.border, lineWidth: 1) + } + } + } + + ForEach(displayableTracks) { track in + trackRow(track) + } + } + .privacySensitive() + } + + private var onboardingCard: some View { + instrumentCard(eyebrow: "03 / BETA", title: "Tester flight plan", accent: RuViewTheme.green) { + Label { + Text("Validate your iPhone's public ARKit LiDAR capabilities before opening the NLOS monitor.") + } icon: { + Image(systemName: "iphone.gen3.radiowaves.left.and.right") + .foregroundStyle(RuViewTheme.green) + } + .font(.subheadline) + .fixedSize(horizontal: false, vertical: true) + + boundaryNotice( + "This test measures visible surfaces only. Every result is labeled DIRECT_DEPTH and is never presented as around the corner evidence.", + color: RuViewTheme.orange + ) + + Link(destination: URL(string: "https://ruview-nlos.ruv.chatgpt.site")!) { + Label("Open the visual explainer", systemImage: "safari") + .frame(maxWidth: .infinity) + } + .buttonStyle(InstrumentPrimaryButtonStyle(accent: RuViewTheme.green)) + .accessibilityHint("Opens the RuView NLOS explainer in your browser") + + Link(destination: URL(string: "https://github.com/ruvnet/RuView/issues/1690")!) { + Label("Test guide and feedback", systemImage: "bubble.left.and.exclamationmark.bubble.right") + .frame(maxWidth: .infinity) + } + .buttonStyle(InstrumentSecondaryButtonStyle(accent: RuViewTheme.green)) + .accessibilityHint("Opens issue 1690 on GitHub") + } + } + private var visibleDepthCard: some View { - card(title: "Visible depth validation") { + instrumentCard(eyebrow: "04 / DEVICE", title: "Visible depth validation", accent: RuViewTheme.orange) { VisibleDepthValidationView( session: model.visibleDepthSession, exportConsent: $exportConsent, @@ -69,228 +276,442 @@ struct ContentView: View { } private var connectionCard: some View { - card(title: "Authenticated stream") { - TextField("wss://host.example/api/v1/nlos/ws", text: $model.endpointText) + instrumentCard(eyebrow: "05 / TRANSPORT", title: "Authenticated stream", accent: RuViewTheme.cyan) { + VStack(alignment: .leading, spacing: 6) { + Text("SECURE ENDPOINT") + .font(.caption2.bold().monospaced()) + .tracking(0.8) + .foregroundStyle(RuViewTheme.muted) + TextField("wss://host.example/api/v1/nlos/ws", text: $model.endpointText) + .textInputAutocapitalization(.never) + .autocorrectionDisabled() + .keyboardType(.URL) + .textContentType(.URL) + .instrumentInput() + .accessibilityLabel("Secure WebSocket endpoint") + } + + VStack(alignment: .leading, spacing: 6) { + Text("PAIRING TOKEN") + .font(.caption2.bold().monospaced()) + .tracking(0.8) + .foregroundStyle(RuViewTheme.muted) + SecureField( + model.storedTokenAvailable ? "Token stored in Keychain" : "Pairing token", + text: $model.pairingToken + ) .textInputAutocapitalization(.never) .autocorrectionDisabled() - .keyboardType(.URL) - .textContentType(.URL) - .padding(12) - .background(Color(uiColor: .tertiarySystemBackground)) - .clipShape(RoundedRectangle(cornerRadius: 10)) + .textContentType(.password) + .instrumentInput() + .accessibilityLabel("Pairing token") + } - SecureField( - model.storedTokenAvailable ? "Pairing token stored in Keychain" : "Pairing token", - text: $model.pairingToken - ) - .textInputAutocapitalization(.never) - .autocorrectionDisabled() - .textContentType(.password) - .padding(12) - .background(Color(uiColor: .tertiarySystemBackground)) - .clipShape(RoundedRectangle(cornerRadius: 10)) - - HStack { - Button(model.isConnected ? "Reconnect" : "Connect") { + VStack(spacing: 10) { + Button(model.isConnected ? "Reconnect secure stream" : "Connect secure stream") { model.connect() } - .buttonStyle(.borderedProminent) + .buttonStyle(InstrumentPrimaryButtonStyle(accent: RuViewTheme.cyan)) if model.isConnected { Button("Disconnect", role: .cancel) { model.disconnect() } - .buttonStyle(.bordered) + .buttonStyle(InstrumentSecondaryButtonStyle(accent: RuViewTheme.cyan)) } - Spacer() - if model.storedTokenAvailable { - Button("Forget token", role: .destructive) { + Button("Forget stored token", role: .destructive) { model.forgetPairingToken() } - .font(.caption) + .frame(minHeight: 44) + .font(.caption.bold().monospaced()) + .foregroundStyle(RuViewTheme.red) } } Label( - "Bearer token stays in this device's Keychain and is sent only over wss.", + "The bearer token stays in this device's Keychain and is sent only over wss.", systemImage: "lock.shield" ) .font(.caption) - .foregroundStyle(.secondary) + .foregroundStyle(RuViewTheme.textSecondary) + .fixedSize(horizontal: false, vertical: true) } } - private var statusCard: some View { - card(title: "Evidence status") { - HStack(alignment: .top) { - Circle() - .fill(statusColor) - .frame(width: 10, height: 10) - .padding(.top, 4) - Text(model.statusMessage) - .font(.subheadline) - Spacer() - } - - if let frame = model.frame { - HStack(spacing: 8) { - badge(frame.source.rawValue.uppercased(), color: sourceColor(frame.source)) - badge(frame.evidenceLevel.rawValue.uppercased(), color: .indigo) - badge("SEQ \(frame.sequence)", color: .gray) - } - .accessibilityElement(children: .combine) - - VStack(alignment: .leading, spacing: 4) { - Text("Sensor: \(frame.provenance.sensorModel)") - Text("Transient: \(frame.provenance.transientKind.rawValue)") - Text("Histogram preserved: \(frame.provenance.histogramPreserved ? "yes" : "no")") - Text("Algorithm: \(frame.algorithmVersion)") - } - .font(.caption.monospaced()) - .foregroundStyle(.secondary) - } - } - } - - private var visualizationCard: some View { - card(title: "Validated hidden target hypotheses") { - ZStack { - TrackCanvas(tracks: model.tracks) - .frame(height: 300) - .privacySensitive() - - if let watermark = model.frame?.watermark { - Text(watermark) - .font(.system(size: 38, weight: .black, design: .rounded)) - .foregroundStyle(.orange.opacity(0.42)) - .rotationEffect(.degrees(-18)) - .accessibilityLabel("Synthetic evidence watermark") - } - - if model.tracks.isEmpty { - Text("NO DISPLAYABLE TRACKS") - .font(.caption.bold().monospaced()) - .foregroundStyle(.secondary) - .padding(10) - .background(.ultraThinMaterial, in: Capsule()) - } - } - - ForEach(model.tracks) { track in - HStack { - VStack(alignment: .leading) { - Text(track.trackId) - .font(.subheadline.monospaced()) - .lineLimit(1) - Text(String( - format: "x %.2f y %.2f z %.2f m", - track.positionM.x, - track.positionM.y, - track.positionM.z - )) - .font(.caption.monospacedDigit()) - .foregroundStyle(.secondary) - } - Spacer() - Text("\(Int(track.confidence * 100))%") - .font(.headline.monospacedDigit()) - badge(track.state.rawValue.uppercased(), color: track.state == .degraded ? .orange : .cyan) - } - .accessibilityElement(children: .combine) - } - } - .privacySensitive() - } - private var capabilityCard: some View { - card(title: "Apple capability probe") { - capabilityRow("ARKit scene depth", model.capabilities.sceneDepth) - capabilityRow("ARKit smoothed depth", model.capabilities.smoothedSceneDepth) - capabilityRow("ARKit scene mesh", model.capabilities.sceneMesh) - capabilityRow("ARKit world pose", model.capabilities.worldPose) - capabilityRow("Raw photon histograms", model.capabilities.rawPhotonHistograms) + instrumentCard(eyebrow: "06 / CAPABILITY", title: "Apple capability probe", accent: RuViewTheme.indigo) { + VStack(spacing: 0) { + capabilityRow("ARKit scene depth", model.capabilities.sceneDepth) + capabilityRow("ARKit smoothed depth", model.capabilities.smoothedSceneDepth) + capabilityRow("ARKit scene mesh", model.capabilities.sceneMesh) + capabilityRow("ARKit world pose", model.capabilities.worldPose) + capabilityRow("Raw photon histograms", model.capabilities.rawPhotonHistograms, isLast: true) + } + .background(RuViewTheme.surface, in: RoundedRectangle(cornerRadius: 12)) Text(model.capabilities.rawPhotonHistogramReason) .font(.caption) - .foregroundStyle(.secondary) + .foregroundStyle(RuViewTheme.textSecondary) .fixedSize(horizontal: false, vertical: true) } } private var boundaryCard: some View { - card(title: "Interpretation boundary") { - Label( + instrumentCard(eyebrow: "07 / BOUNDARY", title: "Interpretation boundary", accent: RuViewTheme.orange) { + boundaryNotice( "This client visualizes validated NLOS output produced by an external transient histogram pipeline.", - systemImage: "waveform.path.ecg.rectangle" + color: RuViewTheme.cyan, + icon: "waveform.path.ecg.rectangle" ) - Label( - "ARKit depth, mesh, and pose are useful context, but this app never labels them as optical NLOS evidence.", - systemImage: "exclamationmark.shield" + boundaryNotice( + "ARKit depth, mesh, and pose are context only. The app never labels them as optical NLOS evidence.", + color: RuViewTheme.orange, + icon: "exclamationmark.shield" ) Text("Unknown, stale, malformed, replayed, oversized, or unauthenticated input is hidden by default.") .font(.caption.bold()) + .foregroundStyle(.white) + .fixedSize(horizontal: false, vertical: true) } - .font(.subheadline) } - private var statusColor: Color { - switch model.connectionState { - case .connected: return .green - case .connecting: return .yellow - case .blocked: return .red - case .disconnected: return .secondary + private var evidenceLegend: some View { + VStack(alignment: .leading, spacing: 10) { + Text("EVIDENCE LEGEND") + .font(.caption2.bold().monospaced()) + .tracking(1.2) + .foregroundStyle(RuViewTheme.muted) + ViewThatFits(in: .horizontal) { + HStack(spacing: 8) { + legendItem("VERIFIED", RuViewTheme.green) + legendItem("UNVERIFIED", RuViewTheme.yellow) + legendItem("SYNTHETIC", RuViewTheme.orange) + } + VStack(alignment: .leading, spacing: 8) { + legendItem("VERIFIED", RuViewTheme.green) + legendItem("UNVERIFIED", RuViewTheme.yellow) + legendItem("SYNTHETIC", RuViewTheme.orange) + } + } + Text("A label describes evidence provenance, not certainty about the physical world.") + .font(.caption2) + .foregroundStyle(RuViewTheme.muted) } + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 4) + .accessibilityElement(children: .combine) + } + + private var evidenceState: EvidencePresentation { + switch model.connectionState { + case .disconnected: + return EvidencePresentation( + label: "DISCONNECTED", + detail: "No authenticated transport is active and no track evidence is displayed.", + color: RuViewTheme.muted, + icon: "antenna.radiowaves.left.and.right.slash" + ) + case .connecting: + return EvidencePresentation( + label: "LIVE UNVERIFIED", + detail: "The secure transport is opening. No evidence is accepted yet.", + color: RuViewTheme.yellow, + icon: "ellipsis" + ) + case .blocked: + let isStale = model.statusMessage.localizedCaseInsensitiveContains("stale") + || model.statusMessage.localizedCaseInsensitiveContains("expired") + return EvidencePresentation( + label: isStale ? "STALE" : (model.isConnected ? "LIVE UNVERIFIED" : "DISCONNECTED"), + detail: "Input failed validation and has been hidden. Reconnect only after resolving the reported cause.", + color: RuViewTheme.red, + icon: "exclamationmark.octagon.fill" + ) + case .connected: + guard let frame = model.frame else { + return EvidencePresentation( + label: "LIVE UNVERIFIED", + detail: "Transport is authenticated, but no validated evidence frame is available.", + color: RuViewTheme.yellow, + icon: "shield.lefthalf.filled" + ) + } + switch frame.source { + case .synthetic: + return EvidencePresentation( + label: "SYNTHETIC", + detail: "Generated evidence is accepted only at L0 and remains visibly watermarked.", + color: RuViewTheme.orange, + icon: "testtube.2" + ) + case .replay: + return EvidencePresentation( + label: "DISCONNECTED", + detail: "Replay provenance is retained below, but recorded tracks are withheld from the live evidence surface.", + color: RuViewTheme.muted, + icon: "arrow.counterclockwise.circle.fill" + ) + case .live: + if frame.evidenceLevel >= .l2Calibrated { + return EvidencePresentation( + label: "LIVE VERIFIED", + detail: "A fresh calibrated live frame passed the fail closed validator.", + color: RuViewTheme.green, + icon: "checkmark.shield.fill" + ) + } + return EvidencePresentation( + label: "LIVE UNVERIFIED", + detail: "A fresh measured live frame passed validation but is not calibrated.", + color: RuViewTheme.yellow, + icon: "shield.lefthalf.filled" + ) + } + } + } + + private var displayableTracks: [NLOSTrack] { + guard model.connectionState == .connected, let frame = model.frame else { + return [] + } + switch frame.source { + case .synthetic: + return model.tracks + case .live where frame.evidenceLevel >= .l2Calibrated: + return model.tracks + case .live, .replay: + return [] + } + } + + private var connectionLabel: String { + switch model.connectionState { + case .disconnected: return "OFFLINE" + case .connecting: return "OPENING" + case .connected: return "SECURE" + case .blocked: return "BLOCKED" + } + } + + private var connectionColor: Color { + switch model.connectionState { + case .disconnected: return RuViewTheme.muted + case .connecting: return RuViewTheme.yellow + case .connected: return RuViewTheme.green + case .blocked: return RuViewTheme.red + } + } + + private var evidenceLabel: String { + guard let frame = model.frame else { return "NONE" } + return frame.evidenceLevel.rawValue.uppercased() + } + + @ViewBuilder + private func frameBadges(_ frame: TrackDisplayFrame) -> some View { + badge(frame.source.rawValue.uppercased(), color: sourceColor(frame.source)) + badge(frame.evidenceLevel.rawValue.uppercased(), color: evidenceState.color) + badge("SEQ \(frame.sequence)", color: RuViewTheme.muted) } private func sourceColor(_ source: NLOSSource) -> Color { switch source { - case .live: return .green - case .replay: return .blue - case .synthetic: return .orange + case .live: return RuViewTheme.cyan + case .replay: return RuViewTheme.indigo + case .synthetic: return RuViewTheme.orange } } + private func headerMetric(eyebrow: String, value: String, color: Color) -> some View { + VStack(alignment: .leading, spacing: 5) { + Text(eyebrow) + .font(.caption2.bold().monospaced()) + .tracking(0.8) + .foregroundStyle(RuViewTheme.muted) + Text(value) + .font(.caption.bold().monospaced()) + .foregroundStyle(color) + .lineLimit(1) + .minimumScaleFactor(0.7) + } + .padding(12) + .frame(maxWidth: .infinity, minHeight: 64, alignment: .leading) + .background(RuViewTheme.panel, in: RoundedRectangle(cornerRadius: 14)) + .overlay { + RoundedRectangle(cornerRadius: 14) + .stroke(color.opacity(0.3), lineWidth: 1) + } + .accessibilityElement(children: .combine) + } + + private func trackRow(_ track: NLOSTrack) -> some View { + HStack(spacing: 12) { + Circle() + .fill(track.state == .degraded ? RuViewTheme.orange : RuViewTheme.cyan) + .frame(width: 8, height: 8) + .shadow( + color: (track.state == .degraded ? RuViewTheme.orange : RuViewTheme.cyan).opacity(0.8), + radius: 4 + ) + VStack(alignment: .leading, spacing: 4) { + Text(track.trackId) + .font(.subheadline.bold().monospaced()) + .lineLimit(1) + Text(String( + format: "x %.2f y %.2f z %.2f m", + track.positionM.x, + track.positionM.y, + track.positionM.z + )) + .font(.caption.monospacedDigit()) + .foregroundStyle(RuViewTheme.textSecondary) + } + Spacer(minLength: 4) + VStack(alignment: .trailing, spacing: 4) { + Text("\(Int(track.confidence * 100))%") + .font(.headline.monospacedDigit()) + badge( + track.state.rawValue.uppercased(), + color: track.state == .degraded ? RuViewTheme.orange : RuViewTheme.cyan + ) + } + } + .padding(12) + .background(RuViewTheme.surface, in: RoundedRectangle(cornerRadius: 12)) + .accessibilityElement(children: .combine) + .accessibilityLabel( + "Track \(track.trackId), \(track.state.rawValue), confidence \(Int(track.confidence * 100)) percent, position x \(track.positionM.x) y \(track.positionM.y) z \(track.positionM.z) meters" + ) + } + private func capabilityRow( _ title: String, - _ availability: AppleCapabilityAvailability + _ availability: AppleCapabilityAvailability, + isLast: Bool = false ) -> some View { - HStack { - Text(title) - Spacer() - Label( - availability.rawValue.capitalized, - systemImage: availability == .available ? "checkmark.circle.fill" : "xmark.circle.fill" - ) - .foregroundStyle(availability == .available ? .green : .secondary) + VStack(spacing: 0) { + HStack(spacing: 12) { + Text(title) + .font(.subheadline) + Spacer() + Label( + availability.rawValue.capitalized, + systemImage: availability == .available ? "checkmark.circle.fill" : "xmark.circle.fill" + ) + .font(.caption.bold().monospaced()) + .foregroundStyle(availability == .available ? RuViewTheme.green : RuViewTheme.muted) + } + .padding(.horizontal, 12) + .frame(minHeight: 48) + if !isLast { + Rectangle() + .fill(RuViewTheme.border) + .frame(height: 1) + .padding(.leading, 12) + } + } + .accessibilityElement(children: .combine) + } + + private func provenanceRow(_ label: String, _ value: String, isLast: Bool = false) -> some View { + VStack(spacing: 0) { + HStack(alignment: .firstTextBaseline, spacing: 12) { + Text(label) + .font(.caption2.bold().monospaced()) + .tracking(0.6) + .foregroundStyle(RuViewTheme.muted) + Spacer() + Text(value) + .font(.caption.monospaced()) + .foregroundStyle(.white) + .multilineTextAlignment(.trailing) + } + .padding(.horizontal, 12) + .frame(minHeight: 44) + if !isLast { + Rectangle() + .fill(RuViewTheme.border) + .frame(height: 1) + .padding(.leading, 12) + } + } + .accessibilityElement(children: .combine) + } + + private func boundaryNotice(_ text: String, color: Color, icon: String = "exclamationmark.shield") -> some View { + Label { + Text(text) + .fixedSize(horizontal: false, vertical: true) + } icon: { + Image(systemName: icon) + .foregroundStyle(color) + } + .font(.caption) + .foregroundStyle(RuViewTheme.textSecondary) + .padding(12) + .frame(maxWidth: .infinity, alignment: .leading) + .background(color.opacity(0.07), in: RoundedRectangle(cornerRadius: 12)) + .overlay { + RoundedRectangle(cornerRadius: 12) + .stroke(color.opacity(0.24), lineWidth: 1) + } + } + + private func legendItem(_ label: String, _ color: Color) -> some View { + HStack(spacing: 5) { + Circle().fill(color).frame(width: 6, height: 6) + Text(label) + .font(.caption2.bold().monospaced()) + .foregroundStyle(RuViewTheme.textSecondary) } - .font(.subheadline) } private func badge(_ text: String, color: Color) -> some View { Text(text) .font(.caption2.bold().monospaced()) .lineLimit(1) + .minimumScaleFactor(0.72) .padding(.horizontal, 8) - .padding(.vertical, 4) - .background(color.opacity(0.14), in: Capsule()) + .frame(minHeight: 28) + .background(color.opacity(0.12), in: Capsule()) + .overlay { + Capsule().stroke(color.opacity(0.25), lineWidth: 1) + } .foregroundStyle(color) } - private func card( + private func instrumentCard( + eyebrow: String, title: String, + accent: Color, @ViewBuilder content: () -> Content ) -> some View { - VStack(alignment: .leading, spacing: 12) { + VStack(alignment: .leading, spacing: 14) { + HStack(spacing: 10) { + Rectangle() + .fill(accent) + .frame(width: 22, height: 2) + .shadow(color: accent.opacity(0.8), radius: 4) + Text(eyebrow) + .font(.caption2.bold().monospaced()) + .tracking(1.1) + .foregroundStyle(accent) + } Text(title) - .font(.headline) + .font(.title3.bold()) + .foregroundStyle(.white) content() } - .padding() + .padding(16) .frame(maxWidth: .infinity, alignment: .leading) - .background(Color(uiColor: .secondarySystemGroupedBackground)) - .clipShape(RoundedRectangle(cornerRadius: 18)) + .background(RuViewTheme.panel, in: RoundedRectangle(cornerRadius: 20)) + .overlay { + RoundedRectangle(cornerRadius: 20) + .stroke(RuViewTheme.border, lineWidth: 1) + } + .shadow(color: accent.opacity(0.06), radius: 18, y: 8) } } @@ -305,33 +726,34 @@ private struct VisibleDepthValidationView: View { var body: some View { VStack(alignment: .leading, spacing: 12) { - HStack { - Text("DIRECT_DEPTH") - .font(.caption.bold().monospaced()) - .padding(.horizontal, 8) - .padding(.vertical, 4) - .background(Color.orange.opacity(0.15), in: Capsule()) - .foregroundStyle(.orange) + HStack(spacing: 8) { + statusBadge("DIRECT_DEPTH", color: RuViewTheme.orange) Spacer() Text(phaseLabel) .font(.caption.bold().monospacedDigit()) + .foregroundStyle(phaseColor) } Text(session.statusMessage) .font(.subheadline) + .foregroundStyle(.white) + .fixedSize(horizontal: false, vertical: true) if isRunning { ProgressView(value: phaseProgress) + .tint(RuViewTheme.orange) + .accessibilityLabel("Validation phase progress") + .accessibilityValue("\(Int(phaseProgress * 100)) percent") LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())], spacing: 8) { metric("FPS", String(format: "%.1f", session.metrics.fps)) - metric("Depth coverage", "\(Int(session.metrics.depthCoverage * 100))%") - metric("Tracking", session.metrics.trackingState) - metric("Movement", String(format: "%.3f m/s", session.metrics.movementMetersPerSecond)) - metric("Thermal", session.metrics.thermalState) - metric("Remaining", "\(session.metrics.phaseSecondsRemaining)s") + metric("DEPTH COVERAGE", "\(Int(session.metrics.depthCoverage * 100))%") + metric("TRACKING", session.metrics.trackingState) + metric("MOVEMENT", String(format: "%.3f m/s", session.metrics.movementMetersPerSecond)) + metric("THERMAL", session.metrics.thermalState) + metric("REMAINING", "\(session.metrics.phaseSecondsRemaining)s") } Button("Cancel validation", role: .cancel, action: cancel) - .buttonStyle(.bordered) + .buttonStyle(InstrumentSecondaryButtonStyle(accent: RuViewTheme.orange)) } else { Button { exportConsent = false @@ -339,22 +761,30 @@ private struct VisibleDepthValidationView: View { exportError = nil start() } label: { - Label(session.diagnostic == nil ? "Start 45 second validation" : "Run again", systemImage: "sensor.tag.radiowaves.forward") + Label( + session.diagnostic == nil ? "Start 45 second validation" : "Run validation again", + systemImage: "sensor.tag.radiowaves.forward" + ) + .frame(maxWidth: .infinity) } - .buttonStyle(.borderedProminent) + .buttonStyle(InstrumentPrimaryButtonStyle(accent: RuViewTheme.orange)) } if session.diagnostic != nil { - Divider() + Rectangle() + .fill(RuViewTheme.border) + .frame(height: 1) diagnosticPreview Toggle(isOn: $exportConsent) { - VStack(alignment: .leading, spacing: 2) { + VStack(alignment: .leading, spacing: 3) { Text("I choose to export aggregate diagnostics") + .font(.subheadline) Text("The JSON contains no images, raw depth, endpoint, token, or raw samples.") .font(.caption) - .foregroundStyle(.secondary) + .foregroundStyle(RuViewTheme.textSecondary) } } + .tint(RuViewTheme.green) .onChange(of: exportConsent) { consent in if !consent { diagnosticURL = nil } } @@ -362,8 +792,9 @@ private struct VisibleDepthValidationView: View { if let diagnosticURL { ShareLink(item: diagnosticURL) { Label("Share diagnostic JSON", systemImage: "square.and.arrow.up") + .frame(maxWidth: .infinity) } - .buttonStyle(.borderedProminent) + .buttonStyle(InstrumentPrimaryButtonStyle(accent: RuViewTheme.green)) } else { Button("Prepare local JSON") { do { @@ -373,14 +804,22 @@ private struct VisibleDepthValidationView: View { exportError = error.localizedDescription } } - .buttonStyle(.bordered) + .buttonStyle(InstrumentSecondaryButtonStyle(accent: RuViewTheme.green)) .disabled(!exportConsent) + .opacity(exportConsent ? 1 : 0.45) } if let exportError { - Text(exportError).font(.caption).foregroundStyle(.red) + Text(exportError) + .font(.caption) + .foregroundStyle(RuViewTheme.red) + .accessibilityLabel("Export error: \(exportError)") } - Link("Open issue 1690 to submit feedback", destination: URL(string: "https://github.com/ruvnet/RuView/issues/1690")!) - .font(.caption) + Link( + "Open issue 1690 to submit feedback", + destination: URL(string: "https://github.com/ruvnet/RuView/issues/1690")! + ) + .font(.caption.bold()) + .frame(minHeight: 44) } } } @@ -401,27 +840,46 @@ private struct VisibleDepthValidationView: View { } } + private var phaseColor: Color { + switch session.state { + case .completed: return RuViewTheme.green + case .failed: return RuViewTheme.red + case .cancelled: return RuViewTheme.muted + default: return RuViewTheme.orange + } + } + private var phaseProgress: Double { let total = session.state == .calibration ? 15.0 : 30.0 return max(0, min(1, (total - Double(session.metrics.phaseSecondsRemaining)) / total)) } private func metric(_ title: String, _ value: String) -> some View { - VStack(alignment: .leading, spacing: 2) { - Text(title).font(.caption).foregroundStyle(.secondary) - Text(value).font(.subheadline.bold().monospacedDigit()).lineLimit(1).minimumScaleFactor(0.7) + VStack(alignment: .leading, spacing: 4) { + Text(title) + .font(.caption2.bold().monospaced()) + .foregroundStyle(RuViewTheme.muted) + Text(value) + .font(.subheadline.bold().monospacedDigit()) + .lineLimit(1) + .minimumScaleFactor(0.65) } .padding(10) - .frame(maxWidth: .infinity, alignment: .leading) - .background(Color(uiColor: .tertiarySystemBackground), in: RoundedRectangle(cornerRadius: 10)) + .frame(maxWidth: .infinity, minHeight: 66, alignment: .leading) + .background(RuViewTheme.surface, in: RoundedRectangle(cornerRadius: 10)) + .overlay { + RoundedRectangle(cornerRadius: 10).stroke(RuViewTheme.border, lineWidth: 1) + } + .accessibilityElement(children: .combine) } @ViewBuilder private var diagnosticPreview: some View { if let diagnostic = session.diagnostic { - VStack(alignment: .leading, spacing: 4) { - Text("Diagnostic preview") - .font(.subheadline.bold()) + VStack(alignment: .leading, spacing: 6) { + Text("DIAGNOSTIC PREVIEW") + .font(.caption.bold().monospaced()) + .foregroundStyle(RuViewTheme.green) Text("Evidence: \(diagnostic.evidenceLabel.rawValue)") Text("Physical NLOS: \(diagnostic.physicalNLOSStatus)") Text("Permission: \(diagnostic.cameraPermission)") @@ -432,10 +890,173 @@ private struct VisibleDepthValidationView: View { Text("Raw sensor export: false") } .font(.caption.monospaced()) - .foregroundStyle(.secondary) - .padding(10) + .foregroundStyle(RuViewTheme.textSecondary) + .padding(12) .frame(maxWidth: .infinity, alignment: .leading) - .background(Color(uiColor: .tertiarySystemBackground), in: RoundedRectangle(cornerRadius: 10)) + .background(RuViewTheme.surface, in: RoundedRectangle(cornerRadius: 12)) + .overlay { + RoundedRectangle(cornerRadius: 12).stroke(RuViewTheme.green.opacity(0.22), lineWidth: 1) + } + .accessibilityElement(children: .combine) + } + } + + private func statusBadge(_ text: String, color: Color) -> some View { + Text(text) + .font(.caption2.bold().monospaced()) + .padding(.horizontal, 9) + .frame(minHeight: 28) + .background(color.opacity(0.12), in: Capsule()) + .overlay { + Capsule().stroke(color.opacity(0.3), lineWidth: 1) + } + .foregroundStyle(color) + } +} + +private struct EvidencePresentation { + let label: String + let detail: String + let color: Color + let icon: String +} + +private enum RuViewTheme { + static let background = Color(red: 0.020, green: 0.035, blue: 0.051) + static let panel = Color(red: 0.036, green: 0.061, blue: 0.078) + static let panelStrong = Color(red: 0.049, green: 0.082, blue: 0.102) + static let surface = Color(red: 0.050, green: 0.082, blue: 0.102) + static let cyan = Color(red: 0.129, green: 0.831, blue: 0.906) + static let green = Color(red: 0.361, green: 1.000, blue: 0.561) + static let orange = Color(red: 1.000, green: 0.612, blue: 0.231) + static let yellow = Color(red: 1.000, green: 0.827, blue: 0.318) + static let red = Color(red: 1.000, green: 0.353, blue: 0.384) + static let indigo = Color(red: 0.490, green: 0.584, blue: 1.000) + static let muted = Color(red: 0.494, green: 0.596, blue: 0.651) + static let textSecondary = Color(red: 0.665, green: 0.733, blue: 0.769) + static let border = cyan.opacity(0.18) +} + +private struct InstrumentGrid: View { + var body: some View { + Canvas { context, size in + var grid = Path() + let spacing: CGFloat = 28 + var x: CGFloat = 0 + while x <= size.width { + grid.move(to: CGPoint(x: x, y: 0)) + grid.addLine(to: CGPoint(x: x, y: size.height)) + x += spacing + } + var y: CGFloat = 0 + while y <= size.height { + grid.move(to: CGPoint(x: 0, y: y)) + grid.addLine(to: CGPoint(x: size.width, y: y)) + y += spacing + } + context.stroke(grid, with: .color(RuViewTheme.cyan.opacity(0.045)), lineWidth: 0.5) + + var topLine = Path() + topLine.move(to: CGPoint(x: 0, y: 1)) + topLine.addLine(to: CGPoint(x: size.width, y: 1)) + context.stroke(topLine, with: .color(RuViewTheme.cyan.opacity(0.8)), lineWidth: 1) + } + .allowsHitTesting(false) + .accessibilityHidden(true) + .ignoresSafeArea() + } +} + +private struct OrbitalSignatureView: View { + let accent: Color + + var body: some View { + Canvas { context, size in + let center = CGPoint(x: size.width / 2, y: size.height / 2) + let rings: [CGFloat] = [0.31, 0.55, 0.82] + for (index, scale) in rings.enumerated() { + let diameter = min(size.width, size.height) * scale + let rect = CGRect( + x: center.x - diameter / 2, + y: center.y - diameter / 2, + width: diameter, + height: diameter + ) + context.stroke( + Path(ellipseIn: rect), + with: .color(accent.opacity(index == rings.count - 1 ? 0.2 : 0.36)), + lineWidth: 1 + ) + } + + var crosshair = Path() + crosshair.move(to: CGPoint(x: center.x, y: 5)) + crosshair.addLine(to: CGPoint(x: center.x, y: size.height - 5)) + crosshair.move(to: CGPoint(x: 5, y: center.y)) + crosshair.addLine(to: CGPoint(x: size.width - 5, y: center.y)) + context.stroke(crosshair, with: .color(accent.opacity(0.2)), lineWidth: 0.5) + + context.fill( + Path(ellipseIn: CGRect(x: center.x - 3, y: center.y - 3, width: 6, height: 6)), + with: .color(accent) + ) + context.fill( + Path(ellipseIn: CGRect(x: center.x + 21, y: center.y - 20, width: 5, height: 5)), + with: .color(RuViewTheme.green) + ) } } } + +private struct InstrumentInputModifier: ViewModifier { + func body(content: Content) -> some View { + content + .font(.body.monospaced()) + .padding(.horizontal, 12) + .frame(minHeight: 50) + .background(RuViewTheme.surface, in: RoundedRectangle(cornerRadius: 12)) + .overlay { + RoundedRectangle(cornerRadius: 12) + .stroke(RuViewTheme.border, lineWidth: 1) + } + } +} + +private extension View { + func instrumentInput() -> some View { + modifier(InstrumentInputModifier()) + } +} + +private struct InstrumentPrimaryButtonStyle: ButtonStyle { + let accent: Color + + func makeBody(configuration: Configuration) -> some View { + configuration.label + .font(.subheadline.bold()) + .foregroundStyle(RuViewTheme.background) + .padding(.horizontal, 14) + .frame(maxWidth: .infinity, minHeight: 48) + .background(accent.opacity(configuration.isPressed ? 0.72 : 1)) + .clipShape(RoundedRectangle(cornerRadius: 12)) + .shadow(color: accent.opacity(configuration.isPressed ? 0.08 : 0.22), radius: 10, y: 4) + } +} + +private struct InstrumentSecondaryButtonStyle: ButtonStyle { + let accent: Color + + func makeBody(configuration: Configuration) -> some View { + configuration.label + .font(.subheadline.bold()) + .foregroundStyle(accent) + .padding(.horizontal, 14) + .frame(maxWidth: .infinity, minHeight: 48) + .background(accent.opacity(configuration.isPressed ? 0.12 : 0.06)) + .overlay { + RoundedRectangle(cornerRadius: 12) + .stroke(accent.opacity(0.42), lineWidth: 1) + } + .clipShape(RoundedRectangle(cornerRadius: 12)) + } +} diff --git a/ui/ios-nlos/App/TrackCanvas.swift b/ui/ios-nlos/App/TrackCanvas.swift index aa0cd6e8..d7f7560e 100644 --- a/ui/ios-nlos/App/TrackCanvas.swift +++ b/ui/ios-nlos/App/TrackCanvas.swift @@ -7,75 +7,148 @@ struct TrackCanvas: View { var body: some View { Canvas { context, size in + var background = Path() + background.addRect(CGRect(origin: .zero, size: size)) + context.fill( + background, + with: .color(Color(red: 0.014, green: 0.029, blue: 0.043)) + ) drawGrid(context: &context, size: size) + drawRadar(context: &context, size: size) + let radiusMeters = max( 5, min(100, tracks.flatMap { [abs($0.positionM.x), abs($0.positionM.z)] }.max() ?? 5) ) for track in tracks { - let point = CGPoint( - x: size.width / 2 + CGFloat(track.positionM.x / radiusMeters) * size.width * 0.45, - y: size.height / 2 - CGFloat(track.positionM.z / radiusMeters) * size.height * 0.45 - ) - let uncertainty = min( - 34, - max(8, CGFloat(sqrt(max(track.covarianceDiagonalM2.x, track.covarianceDiagonalM2.z))) * 14) - ) - let color: Color = track.state == .degraded ? .orange : .cyan - let uncertaintyRect = CGRect( - x: point.x - uncertainty, - y: point.y - uncertainty, - width: uncertainty * 2, - height: uncertainty * 2 - ) - context.stroke( - Path(ellipseIn: uncertaintyRect), - with: .color(color.opacity(0.45)), - lineWidth: 1 - ) - context.fill( - Path(ellipseIn: CGRect(x: point.x - 5, y: point.y - 5, width: 10, height: 10)), - with: .color(color) - ) - context.draw( - Text(String(track.trackId.prefix(12))) - .font(.caption2.monospaced()) - .foregroundColor(.primary), - at: CGPoint(x: point.x, y: point.y + uncertainty + 10) + draw( + track: track, + context: &context, + size: size, + radiusMeters: radiusMeters ) } } - .background(Color(uiColor: .secondarySystemBackground)) .clipShape(RoundedRectangle(cornerRadius: 16)) .overlay { RoundedRectangle(cornerRadius: 16) - .stroke(Color.secondary.opacity(0.25), lineWidth: 1) + .stroke(Color.cyan.opacity(0.24), lineWidth: 1) } + .shadow(color: Color.cyan.opacity(0.08), radius: 16) .accessibilityHidden(true) } + private func draw( + track: NLOSTrack, + context: inout GraphicsContext, + size: CGSize, + radiusMeters: Double + ) { + let point = CGPoint( + x: size.width / 2 + CGFloat(track.positionM.x / radiusMeters) * size.width * 0.43, + y: size.height / 2 - CGFloat(track.positionM.z / radiusMeters) * size.height * 0.43 + ) + let uncertainty = min( + 36, + max(9, CGFloat(sqrt(max(track.covarianceDiagonalM2.x, track.covarianceDiagonalM2.z))) * 14) + ) + let color: Color = track.state == .degraded + ? Color(red: 1.000, green: 0.612, blue: 0.231) + : Color(red: 0.129, green: 0.831, blue: 0.906) + let uncertaintyRect = CGRect( + x: point.x - uncertainty, + y: point.y - uncertainty, + width: uncertainty * 2, + height: uncertainty * 2 + ) + + context.stroke( + Path(ellipseIn: uncertaintyRect), + with: .color(color.opacity(0.5)), + style: StrokeStyle(lineWidth: 1, dash: [4, 3]) + ) + context.fill( + Path(ellipseIn: CGRect(x: point.x - 11, y: point.y - 11, width: 22, height: 22)), + with: .color(color.opacity(0.12)) + ) + context.fill( + Path(ellipseIn: CGRect(x: point.x - 4, y: point.y - 4, width: 8, height: 8)), + with: .color(color) + ) + + let labelPoint = CGPoint( + x: min(max(point.x, 42), size.width - 42), + y: min(point.y + uncertainty + 14, size.height - 12) + ) + context.draw( + Text(String(track.trackId.prefix(12)).uppercased()) + .font(.caption2.bold().monospaced()) + .foregroundColor(.white), + at: labelPoint + ) + } + private func drawGrid(context: inout GraphicsContext, size: CGSize) { - var path = Path() - for fraction in stride( - from: CGFloat(0.1), - through: CGFloat(0.9), - by: CGFloat(0.1) - ) { - let x = size.width * fraction - let y = size.height * fraction - path.move(to: CGPoint(x: x, y: 0)) - path.addLine(to: CGPoint(x: x, y: size.height)) - path.move(to: CGPoint(x: 0, y: y)) - path.addLine(to: CGPoint(x: size.width, y: y)) + var minorGrid = Path() + let spacing: CGFloat = 24 + var x: CGFloat = 0 + while x <= size.width { + minorGrid.move(to: CGPoint(x: x, y: 0)) + minorGrid.addLine(to: CGPoint(x: x, y: size.height)) + x += spacing } - context.stroke(path, with: .color(.secondary.opacity(0.12)), lineWidth: 0.5) + var y: CGFloat = 0 + while y <= size.height { + minorGrid.move(to: CGPoint(x: 0, y: y)) + minorGrid.addLine(to: CGPoint(x: size.width, y: y)) + y += spacing + } + context.stroke(minorGrid, with: .color(Color.cyan.opacity(0.065)), lineWidth: 0.5) var axes = Path() axes.move(to: CGPoint(x: size.width / 2, y: 0)) axes.addLine(to: CGPoint(x: size.width / 2, y: size.height)) axes.move(to: CGPoint(x: 0, y: size.height / 2)) axes.addLine(to: CGPoint(x: size.width, y: size.height / 2)) - context.stroke(axes, with: .color(.secondary.opacity(0.5)), lineWidth: 1) + context.stroke(axes, with: .color(Color.cyan.opacity(0.34)), lineWidth: 1) + } + + private func drawRadar(context: inout GraphicsContext, size: CGSize) { + let center = CGPoint(x: size.width / 2, y: size.height / 2) + let maximumDiameter = min(size.width, size.height) * 0.86 + for fraction in [0.25, 0.5, 0.75, 1.0] as [CGFloat] { + let diameter = maximumDiameter * fraction + context.stroke( + Path(ellipseIn: CGRect( + x: center.x - diameter / 2, + y: center.y - diameter / 2, + width: diameter, + height: diameter + )), + with: .color(Color.cyan.opacity(fraction == 1 ? 0.2 : 0.12)), + lineWidth: 0.8 + ) + } + + var sweep = Path() + sweep.move(to: center) + sweep.addLine(to: CGPoint( + x: center.x + maximumDiameter * 0.31, + y: center.y - maximumDiameter * 0.31 + )) + context.stroke(sweep, with: .color(Color.green.opacity(0.32)), lineWidth: 1) + + context.fill( + Path(ellipseIn: CGRect(x: center.x - 3, y: center.y - 3, width: 6, height: 6)), + with: .color(Color.green.opacity(0.8)) + ) + + context.draw( + Text("RELAY ORIGIN") + .font(.caption2.bold().monospaced()) + .foregroundColor(Color.white.opacity(0.5)), + at: CGPoint(x: center.x, y: center.y + 17) + ) } } diff --git a/ui/mobile/.gitignore b/ui/mobile/.gitignore index d914c328..521c0b36 100644 --- a/ui/mobile/.gitignore +++ b/ui/mobile/.gitignore @@ -6,6 +6,9 @@ node_modules/ # Expo .expo/ dist/ +dist-e2e/ +test-results/ +playwright-report/ web-build/ expo-env.d.ts diff --git a/ui/mobile/e2e/nlos_mobile_ui.yaml b/ui/mobile/e2e/nlos_mobile_ui.yaml new file mode 100644 index 00000000..b858be63 --- /dev/null +++ b/ui/mobile/e2e/nlos_mobile_ui.yaml @@ -0,0 +1,39 @@ +appId: com.ruvnet.wifidensepose +name: RuView NLOS instrument UI evidence flow +--- +- launchApp: + clearState: true +- tapOn: "NLOS" +- assertVisible: + id: "nlos-evidence-state" +- scrollUntilVisible: + element: + id: "nlos-start-synthetic" + direction: DOWN + timeout: 10000 +- tapOn: + id: "nlos-start-synthetic" +- extendedWaitUntil: + visible: + id: "nlos-synthetic-watermark" + timeout: 5000 +- assertVisible: + id: "nlos-synthetic-watermark" +- assertVisible: + id: "nlos-evidence-state" +- scrollUntilVisible: + element: + id: "nlos-beta-setup" + direction: DOWN + timeout: 10000 +- assertVisible: + id: "nlos-beta-setup" +- scrollUntilVisible: + element: + id: "nlos-feedback-link" + direction: DOWN + timeout: 10000 +- assertVisible: + id: "nlos-feedback-link" +- assertVisible: + id: "nlos-explainer-link" diff --git a/ui/mobile/e2e/web/nlos.mobile.spec.ts b/ui/mobile/e2e/web/nlos.mobile.spec.ts new file mode 100644 index 00000000..32c90b97 --- /dev/null +++ b/ui/mobile/e2e/web/nlos.mobile.spec.ts @@ -0,0 +1,109 @@ +import { expect, test, type Page } from '@playwright/test'; +import { mkdir, readFile, stat } from 'node:fs/promises'; +import { extname, resolve, sep } from 'node:path'; + +const screenshotDirectory = resolve( + process.cwd(), + '../../docs/screenshots/consumer-nlos-mobile-ui', +); +const staticBundleDirectory = process.env.RUVIEW_E2E_STATIC_DIR + ? resolve(process.cwd(), process.env.RUVIEW_E2E_STATIC_DIR) + : null; + +const contentTypes: Record = { + '.css': 'text/css; charset=utf-8', + '.html': 'text/html; charset=utf-8', + '.ico': 'image/x-icon', + '.js': 'text/javascript; charset=utf-8', + '.json': 'application/json; charset=utf-8', + '.png': 'image/png', + '.svg': 'image/svg+xml', + '.ttf': 'font/ttf', +}; + +test.beforeEach(async ({ page }) => { + if (!staticBundleDirectory) return; + await page.route('http://ruview.test/**', async (route) => { + const pathname = decodeURIComponent(new URL(route.request().url()).pathname); + let localPath = resolve(staticBundleDirectory, `.${pathname}`); + if (!localPath.startsWith(`${staticBundleDirectory}${sep}`) && localPath !== staticBundleDirectory) { + await route.fulfill({ status: 404, body: 'Not found' }); + return; + } + try { + if ((await stat(localPath)).isDirectory()) localPath = resolve(localPath, 'index.html'); + } catch { + localPath = resolve(staticBundleDirectory, 'index.html'); + } + await route.fulfill({ + status: 200, + contentType: contentTypes[extname(localPath)] ?? 'application/octet-stream', + body: await readFile(localPath), + }); + }); +}); + +const openNlos = async (page: Page) => { + await page.goto('/'); + await page.getByText('NLOS', { exact: true }).last().click(); + await expect(page.getByText('RuView NLOS', { exact: true })).toBeVisible(); + await expect(page.getByTestId('nlos-evidence-state')).toBeVisible(); +}; + +const capture = async (page: Page, name: string) => { + await mkdir(screenshotDirectory, { recursive: true }); + await page.screenshot({ + path: resolve(screenshotDirectory, name), + animations: 'disabled', + caret: 'hide', + }); +}; + +test.describe('RuView NLOS mobile instrument UI', () => { + test('captures the disconnected overview without horizontal overflow', async ({ page }) => { + await openNlos(page); + await page.evaluate(() => window.scrollTo(0, 0)); + + const dimensions = await page.evaluate(() => ({ + viewport: window.innerWidth, + content: document.documentElement.scrollWidth, + })); + const nestedDimensions = await page.getByTestId('nlos-scroll-view').evaluate((element) => ({ + viewport: element.clientWidth, + content: element.scrollWidth, + })); + expect(dimensions.viewport).toBe(390); + expect(dimensions.content).toBeLessThanOrEqual(390); + expect(nestedDimensions.content).toBeLessThanOrEqual(nestedDimensions.viewport + 1); + await expect(page.getByTestId('nlos-evidence-state')).toHaveText('DISCONNECTED'); + + await capture(page, 'overview-390x844.png'); + }); + + test('captures governed setup with fixed explainer and feedback controls', async ({ page }) => { + await openNlos(page); + const setup = page.getByTestId('nlos-beta-setup'); + await setup.scrollIntoViewIfNeeded(); + await expect(setup).toBeVisible(); + await expect(page.getByRole('link', { name: 'OPEN EXPLAINER' })).toBeVisible(); + await expect(page.getByRole('link', { name: 'TEST STEPS AND FEEDBACK' })).toBeVisible(); + + await capture(page, 'setup-390x844.png'); + }); + + test('starts synthetic replay and preserves its visible watermark', async ({ page }) => { + await openNlos(page); + const replay = page.getByRole('button', { name: 'USE SYNTHETIC REPLAY' }); + await replay.scrollIntoViewIfNeeded(); + await replay.click(); + + await expect(page.getByTestId('nlos-synthetic-watermark')).toBeVisible(); + await expect(page.getByTestId('nlos-provenance-badge')).toContainText('SYNTHETIC'); + await expect(page.getByTestId('nlos-evidence-state')).toContainText('SYNTHETIC'); + await page.getByTestId('nlos-provenance-panel').evaluate((element) => { + element.scrollIntoView({ behavior: 'auto', block: 'start' }); + }); + + await capture(page, 'synthetic-390x844.png'); + }); +}); diff --git a/ui/mobile/e2e/web/serve.mjs b/ui/mobile/e2e/web/serve.mjs new file mode 100644 index 00000000..0702e6c4 --- /dev/null +++ b/ui/mobile/e2e/web/serve.mjs @@ -0,0 +1,49 @@ +import { createReadStream, existsSync, statSync } from 'node:fs'; +import { createServer } from 'node:http'; +import { extname, join, normalize, resolve } from 'node:path'; + +const host = '127.0.0.1'; +const port = 4173; +const root = resolve(process.cwd(), 'dist-e2e'); + +const contentTypes = { + '.css': 'text/css; charset=utf-8', + '.html': 'text/html; charset=utf-8', + '.ico': 'image/x-icon', + '.js': 'text/javascript; charset=utf-8', + '.json': 'application/json; charset=utf-8', + '.png': 'image/png', + '.svg': 'image/svg+xml', + '.webp': 'image/webp', +}; + +const resolveRequestPath = (rawUrl) => { + const pathname = decodeURIComponent(new URL(rawUrl ?? '/', `http://${host}`).pathname); + const normalized = normalize(pathname).replace(/^(\.\.[/\\])+/, ''); + const requested = resolve(root, `.${normalized}`); + if (!requested.startsWith(`${root}/`) && requested !== root) return null; + if (existsSync(requested) && statSync(requested).isFile()) return requested; + const nestedIndex = join(requested, 'index.html'); + if (existsSync(nestedIndex) && statSync(nestedIndex).isFile()) return nestedIndex; + return join(root, 'index.html'); +}; + +const server = createServer((request, response) => { + const path = resolveRequestPath(request.url); + if (!path || !existsSync(path)) { + response.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' }); + response.end('Not found'); + return; + } + + response.writeHead(200, { + 'cache-control': 'no-store', + 'content-type': contentTypes[extname(path)] ?? 'application/octet-stream', + 'x-content-type-options': 'nosniff', + }); + createReadStream(path).pipe(response); +}); + +server.listen(port, host, () => { + process.stdout.write(`RuView mobile E2E server listening on http://${host}:${port}\n`); +}); diff --git a/ui/mobile/eslint.config.js b/ui/mobile/eslint.config.js index db7937a5..74f2f113 100644 --- a/ui/mobile/eslint.config.js +++ b/ui/mobile/eslint.config.js @@ -9,7 +9,16 @@ const typescriptFiles = ['**/*.{ts,tsx}']; module.exports = [ { - ignores: ['node_modules/**', 'dist/**', '.expo/**', 'coverage/**', 'src/assets/webview/**'], + ignores: [ + 'node_modules/**', + 'dist/**', + 'dist-e2e/**', + '.expo/**', + 'coverage/**', + 'playwright-report/**', + 'test-results/**', + 'src/assets/webview/**', + ], }, { files: sourceFiles, diff --git a/ui/mobile/jest.config.js b/ui/mobile/jest.config.js index 3a39d3d7..a6ea800a 100644 --- a/ui/mobile/jest.config.js +++ b/ui/mobile/jest.config.js @@ -7,7 +7,12 @@ module.exports = { ...(expoPreset.setupFiles || []), ], setupFilesAfterEnv: ['/jest.setup.ts'], - testPathIgnorePatterns: ['/node_modules/', '/__mocks__/', '/src/__tests__/test-utils.tsx'], + testPathIgnorePatterns: [ + '/node_modules/', + '/__mocks__/', + '/e2e/web/', + '/src/__tests__/test-utils.tsx', + ], transformIgnorePatterns: [ 'node_modules/(?!(expo|expo-.+|react-native|@react-native|react-native-webview|react-native-reanimated|react-native-svg|react-native-safe-area-context|react-native-screens|@react-navigation|@expo|@unimodules|expo-modules-core|react-native-worklets)/)', ], diff --git a/ui/mobile/package-lock.json b/ui/mobile/package-lock.json index b7e8a532..672dabda 100644 --- a/ui/mobile/package-lock.json +++ b/ui/mobile/package-lock.json @@ -33,6 +33,7 @@ }, "devDependencies": { "@eslint/js": "10.0.1", + "@playwright/test": "1.62.1", "@testing-library/jest-native": "^5.4.3", "@testing-library/react-native": "^13.3.3", "@types/jest": "29.5.14", @@ -2864,6 +2865,22 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@playwright/test": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@react-native-async-storage/async-storage": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz", @@ -9952,6 +9969,53 @@ "node": ">=8" } }, + "node_modules/playwright": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/plist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz", diff --git a/ui/mobile/package.json b/ui/mobile/package.json index 19427906..4893c991 100644 --- a/ui/mobile/package.json +++ b/ui/mobile/package.json @@ -9,7 +9,10 @@ "web": "expo start --web", "test": "jest", "typecheck": "tsc --noEmit", - "lint": "eslint ." + "lint": "eslint .", + "build:web:e2e": "expo export --platform web --output-dir dist-e2e", + "serve:web:e2e": "node e2e/web/serve.mjs", + "e2e:web": "playwright test --config playwright.config.ts" }, "dependencies": { "@expo/vector-icons": "^15.0.2", @@ -37,6 +40,7 @@ }, "devDependencies": { "@eslint/js": "10.0.1", + "@playwright/test": "1.62.1", "@testing-library/jest-native": "^5.4.3", "@testing-library/react-native": "^13.3.3", "@types/jest": "29.5.14", diff --git a/ui/mobile/playwright.config.ts b/ui/mobile/playwright.config.ts new file mode 100644 index 00000000..1a67131a --- /dev/null +++ b/ui/mobile/playwright.config.ts @@ -0,0 +1,38 @@ +import { defineConfig } from '@playwright/test'; + +const staticBundleMode = Boolean(process.env.RUVIEW_E2E_STATIC_DIR); + +export default defineConfig({ + testDir: './e2e/web', + fullyParallel: false, + forbidOnly: Boolean(process.env.CI), + retries: process.env.CI ? 1 : 0, + workers: 1, + reporter: process.env.CI ? [['github'], ['list']] : 'list', + timeout: 30_000, + expect: { timeout: 8_000 }, + outputDir: 'test-results/playwright', + use: { + baseURL: staticBundleMode ? 'http://ruview.test' : 'http://127.0.0.1:4173', + viewport: { width: 390, height: 844 }, + colorScheme: 'dark', + locale: 'en-CA', + contextOptions: { reducedMotion: 'reduce' }, + screenshot: 'only-on-failure', + trace: 'retain-on-failure', + launchOptions: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH + ? { + executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH, + args: ['--no-sandbox', '--disable-dev-shm-usage'], + } + : undefined, + }, + webServer: staticBundleMode + ? undefined + : { + command: 'npm run build:web:e2e && npm run serve:web:e2e', + url: 'http://127.0.0.1:4173', + reuseExistingServer: !process.env.CI, + timeout: 120_000, + }, +}); diff --git a/ui/mobile/src/__tests__/screens/NLOSScreen.test.tsx b/ui/mobile/src/__tests__/screens/NLOSScreen.test.tsx index 47944ac1..27001a1a 100644 --- a/ui/mobile/src/__tests__/screens/NLOSScreen.test.tsx +++ b/ui/mobile/src/__tests__/screens/NLOSScreen.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Linking } from 'react-native'; +import { Linking, StyleSheet } from 'react-native'; import { fireEvent, render, screen } from '@testing-library/react-native'; import { createSyntheticNlosFrame } from '@/services/nlos.service'; import { createLiveNlosFrameFixture } from '@/testUtils/nlosFixtures'; @@ -9,6 +9,14 @@ import { NLOS_EXPLAINER_URL, NLOS_FEEDBACK_URL, } from '@/screens/NLOSScreen/BetaSetupCard'; +import { resolveNlosEvidenceState } from '@/screens/NLOSScreen/ProvenancePanel'; + +const mockSafeAreaInsets = { top: 0, right: 0, bottom: 0, left: 0 }; + +jest.mock('react-native-safe-area-context', () => ({ + ...jest.requireActual('react-native-safe-area-context'), + useSafeAreaInsets: () => mockSafeAreaInsets, +})); const syntheticFrame = createSyntheticNlosFrame(0, 1_700_000_000_000); const mockNlosResult: Record = { @@ -44,6 +52,7 @@ jest.mock('react-native-svg', () => { describe('NLOSScreen', () => { beforeEach(() => { + Object.assign(mockSafeAreaInsets, { top: 0, right: 0, bottom: 0, left: 0 }); Object.assign(mockNlosResult, { frame: syntheticFrame, freshness: 'fresh', @@ -54,6 +63,8 @@ describe('NLOSScreen', () => { }); mockNlosResult.configureCredential.mockClear(); mockNlosResult.forgetCredential.mockClear(); + mockNlosResult.startReplay.mockClear(); + mockNlosResult.connectLive.mockClear(); }); it('renders the RuView NLOS screen and iPhone API boundary', () => { @@ -64,6 +75,20 @@ describe('NLOSScreen', () => { expect(screen.getByText(/web client cannot capture ARKit LiDAR or raw timing data/)).toBeTruthy(); }); + it('keeps the instrument content inside supplied iPhone safe area insets', () => { + Object.assign(mockSafeAreaInsets, { top: 47, right: 3, bottom: 34, left: 3 }); + const { NLOSScreen } = require('@/screens/NLOSScreen'); + render(); + + const contentStyle = StyleSheet.flatten( + screen.getByTestId('nlos-scroll-view').props.contentContainerStyle, + ); + expect(contentStyle.paddingTop).toBe(71); + expect(contentStyle.paddingRight).toBe(19); + expect(contentStyle.paddingBottom).toBe(106); + expect(contentStyle.paddingLeft).toBe(19); + }); + it('provides platform-specific beta setup without browser API assumptions', () => { const ios = getBetaPlatformGuidance('ios'); const web = getBetaPlatformGuidance('web'); @@ -107,6 +132,16 @@ describe('NLOSScreen', () => { render(); expect(screen.getByTestId('nlos-synthetic-watermark')).toBeTruthy(); expect(screen.getByTestId('nlos-provenance-badge').props.children).toBe('SYNTHETIC'); + expect(screen.getByTestId('nlos-evidence-state').props.children).toBe('SYNTHETIC'); + }); + + it('starts deterministic replay from the primary synthetic control', () => { + const { NLOSScreen } = require('@/screens/NLOSScreen'); + render(); + + fireEvent.press(screen.getByTestId('nlos-start-synthetic')); + + expect(mockNlosResult.startReplay).toHaveBeenCalledTimes(1); }); it('does not enable live without an ephemeral credential', () => { @@ -139,13 +174,17 @@ describe('NLOSScreen', () => { const { NLOSScreen } = require('@/screens/NLOSScreen'); render(); expect(screen.getByTestId('nlos-provenance-badge').props.children).toBe('UNKNOWN'); + expect(screen.getByTestId('nlos-evidence-state').props.children).toBe('DISCONNECTED'); + expect(screen.getByTestId('nlos-track-count').props.children).toBe(0); + expect(screen.queryByText('target-1')).toBeNull(); expect(screen.queryByTestId('nlos-synthetic-watermark')).toBeNull(); expect(screen.getByText(/Unknown evidence is never promoted to live/)).toBeTruthy(); }); it('keeps stale measured frames visibly stale', () => { + const live = createLiveNlosFrameFixture(); Object.assign(mockNlosResult, { - frame: createLiveNlosFrameFixture(), + frame: live, freshness: 'stale', streamStatus: 'error', liveCredentialAvailable: true, @@ -153,9 +192,11 @@ describe('NLOSScreen', () => { const { NLOSScreen } = require('@/screens/NLOSScreen'); render(); expect(screen.getByTestId('nlos-stale-overlay')).toBeTruthy(); + expect(screen.getByTestId('nlos-evidence-state').props.children).toBe('STALE'); expect(screen.getByTestId('nlos-freshness-badge').props.children).toBe('STALE'); expect(screen.getByTestId('nlos-track-count').props.children).toBe(0); expect(screen.getByTestId('nlos-mean-confidence').props.children).toBe('N/A'); + expect(screen.queryByText(live.tracks[0].trackId)).toBeNull(); expect(screen.queryByTestId('nlos-synthetic-watermark')).toBeNull(); }); @@ -175,4 +216,100 @@ describe('NLOSScreen', () => { expect(screen.getByTestId('nlos-mean-confidence').props.children).toBe('N/A'); expect(screen.queryByText(live.tracks[0].trackId)).toBeNull(); }); + + it('distinguishes verified and unverified live evidence without changing source labels', () => { + const calibrated = createLiveNlosFrameFixture(); + const measured = createLiveNlosFrameFixture({ evidenceLevel: 'l1_measured' }); + + expect(resolveNlosEvidenceState(calibrated, 'fresh', 'live')).toBe('LIVE VERIFIED'); + expect(resolveNlosEvidenceState(measured, 'fresh', 'live')).toBe('LIVE UNVERIFIED'); + expect(resolveNlosEvidenceState(calibrated, 'stale', 'error')).toBe('STALE'); + expect(resolveNlosEvidenceState(null, 'unknown', 'idle')).toBe('DISCONNECTED'); + expect(resolveNlosEvidenceState(null, 'unknown', 'connecting')).toBe('LIVE UNVERIFIED'); + }); + + it('withholds geometry for unverified live and replay provenance', () => { + const live = createLiveNlosFrameFixture({ evidenceLevel: 'l1_measured' }); + Object.assign(mockNlosResult, { + frame: live, + freshness: 'fresh', + streamStatus: 'live', + }); + const { NLOSScreen } = require('@/screens/NLOSScreen'); + const view = render(); + + expect(screen.getByTestId('nlos-evidence-state').props.children).toBe('LIVE UNVERIFIED'); + expect(screen.getByTestId('nlos-track-count').props.children).toBe(0); + expect(screen.queryByText(live.tracks[0].trackId)).toBeNull(); + + Object.assign(mockNlosResult, { + frame: { ...live, source: 'replay' }, + freshness: 'fresh', + streamStatus: 'live', + }); + view.rerender(); + + expect(screen.getByTestId('nlos-evidence-state').props.children).toBe('DISCONNECTED'); + expect(screen.getByTestId('nlos-provenance-badge').props.children).toBe('REPLAY'); + expect(screen.getByTestId('nlos-track-count').props.children).toBe(0); + expect(screen.queryByText(live.tracks[0].trackId)).toBeNull(); + }); + + it('projects a no-frame live attempt as unverified while withholding geometry', () => { + Object.assign(mockNlosResult, { + frame: null, + freshness: 'unknown', + streamStatus: 'connecting', + }); + const { NLOSScreen } = require('@/screens/NLOSScreen'); + render(); + + expect(screen.getByTestId('nlos-evidence-state').props.children).toBe('LIVE UNVERIFIED'); + expect(screen.getByTestId('nlos-track-count').props.children).toBe(0); + expect(screen.queryByText('target-1')).toBeNull(); + }); + + it('shows geometry only after a fresh live frame passes the verification gate', () => { + const live = createLiveNlosFrameFixture(); + Object.assign(mockNlosResult, { + frame: live, + freshness: 'fresh', + streamStatus: 'live', + }); + const { NLOSScreen } = require('@/screens/NLOSScreen'); + render(); + + expect(screen.getByTestId('nlos-evidence-state').props.children).toBe('LIVE VERIFIED'); + expect(screen.getByTestId('nlos-track-count').props.children).toBe(1); + expect(screen.getByText(live.tracks[0].trackId)).toBeTruthy(); + }); + + it('does not override validator accepted USB sensor provenance in the UI', () => { + const base = createLiveNlosFrameFixture(); + const usbFrame = createLiveNlosFrameFixture({ + provenance: { ...base.provenance, transport: 'usb_serial' }, + }); + + expect(resolveNlosEvidenceState(usbFrame, 'fresh', 'live')).toBe('LIVE VERIFIED'); + }); + + it('keeps privacy, setup, explainer, and feedback controls visible in the screen tree', () => { + const { NLOSScreen } = require('@/screens/NLOSScreen'); + render(); + + expect(screen.getByTestId('nlos-privacy-legend')).toBeTruthy(); + expect(screen.getByTestId('nlos-beta-setup')).toBeTruthy(); + expect(screen.getByTestId('nlos-explainer-link')).toBeTruthy(); + expect(screen.getByTestId('nlos-feedback-link')).toBeTruthy(); + expect(screen.getByText(/Viewer retention: raw RF off, audio off/)).toBeTruthy(); + }); + + it('switches between plan and perspective instrument views', () => { + const { NLOSScreen } = require('@/screens/NLOSScreen'); + render(); + + expect(screen.getByTestId('nlos-view-plan').props.accessibilityState.selected).toBe(true); + fireEvent.press(screen.getByTestId('nlos-view-perspective')); + expect(screen.getByTestId('nlos-view-perspective').props.accessibilityState.selected).toBe(true); + }); }); diff --git a/ui/mobile/src/components/InstrumentPanel.tsx b/ui/mobile/src/components/InstrumentPanel.tsx new file mode 100644 index 00000000..05d1e019 --- /dev/null +++ b/ui/mobile/src/components/InstrumentPanel.tsx @@ -0,0 +1,155 @@ +import type { ReactNode } from 'react'; +import { StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native'; +import { ThemedText } from './ThemedText'; + +export const instrumentColors = { + background: '#05090D', + panel: '#091218', + panelRaised: '#0C171E', + cyan: '#24D3E5', + green: '#58F28B', + cyanDim: 'rgba(36, 211, 229, 0.38)', + greenDim: 'rgba(88, 242, 139, 0.36)', + border: 'rgba(65, 204, 219, 0.22)', + borderStrong: 'rgba(65, 204, 219, 0.42)', + grid: 'rgba(92, 151, 162, 0.065)', + text: '#F3F8FA', + textSecondary: '#91A4AE', + warning: '#FFB65C', + danger: '#FF6478', + dimOverlay: 'rgba(5, 9, 13, 0.78)', +} as const; + +interface InstrumentPanelProps { + children?: ReactNode; + eyebrow?: string; + accessory?: ReactNode; + style?: StyleProp; + testID?: string; + accessibilityLabel?: string; +} + +export const InstrumentGrid = () => ( + + + {Array.from({ length: 8 }, (_, index) => ( + + ))} + + + {Array.from({ length: 18 }, (_, index) => ( + + ))} + + +); + +export const InstrumentPanel = ({ + children, + eyebrow, + accessory, + style, + testID, + accessibilityLabel, +}: InstrumentPanelProps) => ( + + + + + + + + {(eyebrow || accessory) && ( + + {eyebrow ? ( + {eyebrow} + ) : } + {accessory} + + )} + {children} + +); + +const styles = StyleSheet.create({ + gridColumns: { + ...StyleSheet.absoluteFillObject, + flexDirection: 'row', + }, + gridColumn: { + flex: 1, + borderRightColor: instrumentColors.grid, + borderRightWidth: 1, + }, + gridRows: { + ...StyleSheet.absoluteFillObject, + justifyContent: 'space-between', + }, + gridRow: { + height: 1, + backgroundColor: instrumentColors.grid, + }, + panel: { + position: 'relative', + overflow: 'hidden', + backgroundColor: instrumentColors.panel, + borderColor: instrumentColors.border, + borderWidth: 1, + borderRadius: 18, + padding: 16, + gap: 12, + shadowColor: instrumentColors.cyan, + shadowOffset: { width: 0, height: 10 }, + shadowOpacity: 0.07, + shadowRadius: 24, + elevation: 2, + }, + accentRail: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + height: 2, + flexDirection: 'row', + }, + accentRailCyan: { flex: 2, backgroundColor: instrumentColors.cyan }, + accentRailGreen: { flex: 1, backgroundColor: instrumentColors.green }, + corner: { + position: 'absolute', + width: 11, + height: 11, + borderColor: instrumentColors.cyanDim, + }, + cornerTopLeft: { + top: 7, + left: 7, + borderTopWidth: 1, + borderLeftWidth: 1, + }, + cornerBottomRight: { + right: 7, + bottom: 7, + borderRightWidth: 1, + borderBottomWidth: 1, + }, + headingRow: { + minHeight: 22, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + flexWrap: 'wrap', + gap: 8, + }, + eyebrow: { + color: instrumentColors.cyan, + fontSize: 11, + lineHeight: 16, + letterSpacing: 1.4, + textTransform: 'uppercase', + }, +}); diff --git a/ui/mobile/src/screens/NLOSScreen/BetaSetupCard.tsx b/ui/mobile/src/screens/NLOSScreen/BetaSetupCard.tsx index c00dc15c..e20f55d2 100644 --- a/ui/mobile/src/screens/NLOSScreen/BetaSetupCard.tsx +++ b/ui/mobile/src/screens/NLOSScreen/BetaSetupCard.tsx @@ -1,6 +1,6 @@ import { Linking, Platform, Pressable, StyleSheet, View } from 'react-native'; +import { InstrumentPanel, instrumentColors } from '@/components/InstrumentPanel'; import { ThemedText } from '@/components/ThemedText'; -import { colors } from '@/theme/colors'; import { spacing } from '@/theme/spacing'; export const NLOS_EXPLAINER_URL = 'https://ruview-nlos.ruv.chatgpt.site'; @@ -65,8 +65,19 @@ const openTrustedUrl = async (url: string): Promise => { } }; -const LinkButton = ({ label, url, primary = false }: { label: string; url: string; primary?: boolean }) => ( +const LinkButton = ({ + label, + url, + primary = false, + testID, +}: { + label: string; + url: string; + primary?: boolean; + testID?: string; +}) => ( { const guidance = getBetaPlatformGuidance(currentBetaPlatform()); return ( - + - BETA SETUP + BETA SETUP {guidance.label} - Start a governed test in about five minutes + Start a governed test in about five minutes {guidance.steps.map((step, index) => ( @@ -102,41 +118,53 @@ export const BetaSetupCard = () => { CAPABILITY BOUNDARY - + The web client cannot capture ARKit LiDAR or raw timing data. It only displays synthetic replay or validated tracks produced by a RuView server. - - Compatibility: any supported device can view tracks. A LiDAR equipped iPhone Pro or iPad Pro is needed only for separately assigned hardware capability checks. - - - Evidence labels: L0 synthetic, L1 measured, L2 calibrated, or L3 corroborated, plus fresh, stale, or unknown. Depth only input is never physical NLOS evidence. - + + + DEVICE + + Compatibility: any supported device can view tracks. A LiDAR equipped iPhone Pro or iPad Pro is needed only for separately assigned hardware capability checks. + + + + EVIDENCE + + Evidence labels: L0 synthetic, L1 measured, L2 calibrated, or L3 corroborated, plus fresh, stale, or unknown. Depth only input is never physical NLOS evidence. + + + {guidance.showTestFlightButton && ( )} - - + + - + No credentials are saved by setup. Live pairing credentials remain in memory only and can be forgotten at any time. - + ); }; const styles = StyleSheet.create({ card: { - backgroundColor: colors.surface, - borderColor: colors.accentDim, - borderWidth: 1, - borderRadius: 12, - padding: spacing.lg, - gap: spacing.md, + backgroundColor: instrumentColors.panelRaised, }, headingRow: { flexDirection: 'row', @@ -145,48 +173,84 @@ const styles = StyleSheet.create({ flexWrap: 'wrap', gap: spacing.sm, }, + sectionLabel: { color: instrumentColors.text }, platformBadge: { - color: colors.accent, - borderColor: colors.accentDim, + color: instrumentColors.cyan, + borderColor: instrumentColors.cyanDim, borderWidth: 1, borderRadius: 999, paddingHorizontal: spacing.sm, paddingVertical: spacing.xs, }, - title: { lineHeight: 23 }, + title: { + maxWidth: 300, + color: instrumentColors.text, + fontSize: 25, + lineHeight: 30, + letterSpacing: -0.45, + }, steps: { gap: spacing.sm }, - stepRow: { flexDirection: 'row', alignItems: 'flex-start', gap: spacing.sm }, + stepRow: { + minHeight: 44, + flexDirection: 'row', + alignItems: 'flex-start', + gap: spacing.md, + borderBottomColor: instrumentColors.grid, + borderBottomWidth: 1, + paddingBottom: spacing.sm, + }, stepNumber: { - color: colors.bg, - backgroundColor: colors.accent, + color: instrumentColors.background, + backgroundColor: instrumentColors.cyan, borderRadius: 999, - width: 24, - height: 24, - lineHeight: 24, + width: 28, + height: 28, + lineHeight: 28, textAlign: 'center', }, - stepText: { flex: 1, lineHeight: 21 }, + stepText: { flex: 1, lineHeight: 21, color: instrumentColors.text }, boundary: { - backgroundColor: 'rgba(255, 165, 2, 0.08)', - borderLeftColor: colors.warn, + backgroundColor: 'rgba(255, 182, 92, 0.07)', + borderColor: 'rgba(255, 182, 92, 0.24)', + borderWidth: 1, + borderLeftColor: instrumentColors.warning, borderLeftWidth: 3, + borderRadius: 10, padding: spacing.md, gap: spacing.xs, }, - boundaryLabel: { color: colors.warn }, + boundaryLabel: { color: instrumentColors.warning }, + boundaryCopy: { color: instrumentColors.text }, + compatibilityGrid: { gap: spacing.sm }, + compatibilityCell: { + backgroundColor: 'rgba(5, 9, 13, 0.38)', + borderColor: instrumentColors.border, + borderWidth: 1, + borderRadius: 10, + padding: spacing.md, + gap: spacing.xs, + }, + cellLabel: { + color: instrumentColors.green, + fontSize: 10, + letterSpacing: 1.2, + }, + cellCopy: { color: instrumentColors.textSecondary, lineHeight: 18 }, links: { flexDirection: 'row', flexWrap: 'wrap', gap: spacing.sm }, linkButton: { - minHeight: 44, + minHeight: 48, flexGrow: 1, + flexBasis: 150, alignItems: 'center', justifyContent: 'center', - borderColor: colors.accent, + borderColor: instrumentColors.cyanDim, borderWidth: 1, - borderRadius: 8, + borderRadius: 10, paddingHorizontal: spacing.md, paddingVertical: spacing.sm, }, - linkButtonPrimary: { backgroundColor: colors.accent }, - linkButtonText: { color: colors.accent, textAlign: 'center' }, - linkButtonPrimaryText: { color: colors.bg, textAlign: 'center' }, + linkButtonPrimary: { backgroundColor: instrumentColors.cyan }, + linkButtonText: { color: instrumentColors.cyan, textAlign: 'center' }, + linkButtonPrimaryText: { color: instrumentColors.background, textAlign: 'center' }, + retentionNote: { color: instrumentColors.textSecondary, lineHeight: 18 }, }); diff --git a/ui/mobile/src/screens/NLOSScreen/HiddenTargetVisualization.tsx b/ui/mobile/src/screens/NLOSScreen/HiddenTargetVisualization.tsx index 7db3ae15..33ef64a2 100644 --- a/ui/mobile/src/screens/NLOSScreen/HiddenTargetVisualization.tsx +++ b/ui/mobile/src/screens/NLOSScreen/HiddenTargetVisualization.tsx @@ -1,7 +1,7 @@ import React, { memo, useMemo } from 'react'; import { View } from 'react-native'; import Svg, { Circle, Ellipse, Line, Polygon, Rect, Text as SvgText } from 'react-native-svg'; -import { colors } from '@/theme/colors'; +import { instrumentColors } from '@/components/InstrumentPanel'; import type { NlosFreshness, NlosTrack } from '@/types/nlos'; export type NlosViewMode = 'plan' | 'perspective'; @@ -29,9 +29,9 @@ const CANVAS_HEIGHT = 260; const clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value)); const resolveTrackColor = (track: NlosTrack, freshness: NlosFreshness): string => { - if (freshness !== 'fresh' || track.state === 'unknown') return colors.muted; - if (track.state === 'degraded') return colors.warn; - return colors.accent; + if (freshness !== 'fresh' || track.state === 'unknown') return instrumentColors.textSecondary; + if (track.state === 'degraded') return instrumentColors.warning; + return instrumentColors.green; }; const projectPlan = (track: NlosTrack): ProjectedTrack => { @@ -65,27 +65,45 @@ const projectPerspective = (track: NlosTrack): ProjectedTrack => { const PlanScene = () => ( <> - - - - HIDDEN REGION - RELAY SURFACE - - - SENSOR + + {[60, 108, 156, 204, 252, 300].map((x) => ( + + ))} + {[54, 94, 134, 174, 214].map((y) => ( + + ))} + + + HIDDEN REGION + RELAY SURFACE + + + + + + + SENSOR ); const PerspectiveScene = () => ( <> - - - - - - - BEYOND RELAY PLANE - + + + + + {[1, 2, 3].map((step) => ( + + + + + ))} + + + + BEYOND RELAY PLANE + + ); @@ -103,6 +121,7 @@ export const HiddenTargetVisualization = memo(({ return (