Skip to content

fix(native): match the web aurora, glass cards, ticker and remaining UI audit rows (batch 3) - #444

Merged
EraPartner merged 17 commits into
mainfrom
claude/project-thread-eaczlm
Nov 14, 2026
Merged

EraPartner merged 17 commits into
mainfrom
claude/project-thread-eaczlm

Conversation

@EraPartner

@EraPartner EraPartner commented Nov 14, 2026 •

Copy link
Copy Markdown
Owner

Requested by EraPartner · project thread

Summary

Batch 3 of the 2026-11-14 Swift vs TypeScript UI audit, plus Tor's polish asks from the same day (chart hover motion, Sankey hover, API monitor, topbar). The TS app is the reference. Draft #440's aurora, card and ticker work is taken over here (adapted), so #440 is superseded once this merges.

Audit row Cause found in code Change
K1 / S-03 background The wash was an EllipticalGradient ending at 0.6 of a 3840 pt frame (twice the CSS 120rem 60rem … 60% radius). The grain was 8/16/32-cell value noise, a blotchy texture, opaque Wash ends at 0.3; grain is per-pixel three-octave noise with noisy alpha like feTurbulence fractalNoise 0.8 (from #440)
K2 / S-04 cards Core Animation drew each card's shadow under the whole card, so it showed through the translucent glass. The lift layer with a nil colour cast CA's default black shadow. Full effects cards were drawn by SwiftUI (CPU) with a unit-square 135° gradient Shadows are masked to the outside of the card, as a CSS box-shadow is (from #440). Both materials (glass-thin, glass-regular) are drawn as CA layers on the CSS gradient line (|w sin a| + |h cos a|). Dark Full effects frame is --glass-border/0.08, which wins the cascade over .premium-frame
K3 ticker visible started false and only onScrollVisibilityChange set it, so the tape could stay inactive: no quote fetch, no motion. An empty price_provider_id did not fall back to the symbol in the view (it does in the model) Starts active as on the web; natural tile widths with measured tape width (from #440); .ticker-mask 4 % edge fade; liquid-glass box with elevation-2 shadows instead of a Card; hover pauses only the tape; placeholder shows only for all-hidden or offline
S-48 Full effects default Swift read fullEffects as a boolean; the backend stores "auto" (ADR-255), which read as off New FullEffectsChoice (auto/on/off, old boolean read like settingsStore.ts), resolved with the chosen tier; the switch writes on/off
K4 colours (part) System colours leaking past the theme: API inspector used .blue; the report sheet used the system segmented picker and checkbox Theme info; VisionSegmentedControl and visionCheckbox. Badge tones checked against badge.tsx: they match
S-06, S-66 topbar The sidebar trigger only showed with the sidebar hidden, plus a search button the web hides on desktop (md:hidden) Trigger always shown, no search button (the sidebar and its rail keep search)
S-07 compact title Topbar showed the sidebar item name ("Home") Page header title via a preference (usePageTitle); veil from 8 pt, title from 96 pt like AppLayout
S-08 page icons Several headers had their own SF Symbols Headers read PAGE_ICONS through the generated registry (VisionPageSymbol): Net worth, Forecast, Compare, Chart builder, Analysis, AI chat, Dossiers, portfolio import, tax print
S-65 focus rings The field chrome used the container's isFocused, which is true for every field in a focused panel Ignores focus owned by the page/panel container, as VisionFocusRingModifier already does
S-68 Customize dialog List fixed at 420 pt, so 8 of 11 rows showed and the sheet was taller than needed Content height, scrolling only past 60 % of the window (max-h-[60vh])
S-41 / S-89 asset-class tiles 230 pt adaptive grid, alphabetical, portfolio.assetClass.* labels lg:grid-cols-3 compact cards, first-appearance order, performance.* labels, layout from PerformanceBreakdown.tsx
S-88 / S-40 heat map cells Radius.sm, 8 pt padding, pill tooltip rounded-control, py-1.5, native title tooltip, en dash for empty months
S-36 Sankey header Exclusion chip after the year select Chip first, as in SankeyTab.tsx
S-107 About Eye symbol, bundle name ("Vision Native Demo"), arrow labels Vision mark, APP_NAME "Vision", label then external-link icon
S-46 / S-94 savings & bonds Label/value rows, plain glyph, bonds could come first (filtered active order); maturing colour was warning SavingsPage card: 40 pt tinted tile, type badge + accent rate, balance and interest earned as a title-2 pair, FactRow list, matured accent / maturing-soon primary border; holdings grouped in class order like byAssetClass. S-94: the extra accrued stat is in the TS source too
S-87 market news Count as caption, plain link title, abbreviated relative time, joined ticker text NewsItem: count badge, whole row is the link with foreground/0.04 hover, primary title and external-link glyph on hover, clock + formatDistanceToNow units, outline ticker badges, compact empty states
S-15 Last 6 months axis Used formatAxisCompact formatCurrencyCompact (full amount up to 9 chars, otherwise locale compact) as MonthlyTrendsChart does
S-83 tax year menu Native Menu, one badge string per year, current won over filed VisionMenu with the eyebrow label, year + lock/snowflake icon, YearStatusBadge tones and precedence
S-63 filter / view menus Native menus Transactions date, type and View menus are VisionMenu panels; VisionMenu gains radio/checkbox items and VisionMenuLabel
S-91 daily breakdown Whole table inside a 520 pt ScrollView (header scrolled away) Rows scroll under the header (bodyMaxHeight(520))
Donut hover (Tor) Slice and centre changed at once DonutChart: arc grows 4.5 % over durations.slow out-expo, centre swaps via a 0.15 s fade out then 0.15 s fade/scale in; none under Reduce Motion. TS has no hover-intent timer; this is its whole "gradual" feel
Chart tooltip (Tor) Appeared at once ChartTooltip enter (opacity, y + 4) and exit (opacity, y + 2) over durations.fast out-expo
Sankey hover (Tor) One chart-wide tracker tested node rectangles first, so a band beside a node lit the node's whole section Each bar and band tracks its own hover on its own shape (SVG onMouseEnter/onMouseLeave), bars over bands, labels take no pointer
API monitor (Tor) regularMaterial capsule and panel, system segmented tabs, system colours InspectorToggle outline pill (mono footnote, elevation-2, hover/open colours), opaque card panel with border and elevation-4, underline tabs, ghost icon buttons, theme method colours; Queries tab kept
Topbar (Tor) Traffic lights at AppKit's default spot above a 28 pt strip; a flat band under the titlebar Traffic lights at Electron's trafficLightPosition (20, 20), the 56 pt h-14 bar with a ghost h-7 trigger on that line, .app-topbar veil values, scrollEdgeEffectHidden for the top edge

Checked and left alone (code matches the TS source): S-16, S-37, S-50 (cause unknown, unverified), S-86, S-90, S-95, S-101, S-108.

Left open on purpose: S-25 (transactions table inner scroller). The Swift page's infinite loading and scroll restoration run on the page scroll; it needs a runtime check first.

PR #440: this branch takes #440's AuroraCanvas.swift and PortfolioTickerView.swift and re-implements its card shadow fix in a reworked VisionCardLayers. Everything else in #440 landed in #441/#442. #440 is superseded.

Type of change

  • fix — bug fix

Checklist

  • Conventional Commit title
  • bun scripts/native-lint.ts: native-lint ok (string-literal-compare 702, baseline 716)
  • Swift compile and tests: macOS CI Swift app (macOS) passed on 66e82e0
  • Docs: docs/reference/native-parity/shell-and-settings.md (Full effects auto default; topbar and traffic-light position)
  • No new strings; no API or schema change

Verification

  • Compiled and unit-tested only in CI. Nothing was run on a Mac: every row above is unverified in the running app. The traffic-light placement (moving AppKit's titlebar buttons on resize, key and full-screen exit) is the riskiest change.

Residual risk & follow-ups

  • No backdrop saturate in SwiftUI: the web card's saturate(150%) over the aurora is not reproduced.
  • Full effects cards moved from SwiftUI drawing to Core Animation layers; the hover transition runs through CATransaction.
  • Existing installs that stored fullEffects: false now read it as auto (on with Standard), as the web store does.
  • currencyCompact uses Foundation's compact notation; ICU output should match Intl, not checked per locale.
  • AppKit may re-lay out the titlebar buttons on events not hooked here; if the lights jump back, the hook list needs extending.

🤖 Generated with Claude Code

https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B

…effects default

UI audit batch 3 (K1, K2, K3, S-48), TS app as the reference:
- Aurora wash ends at the web radius and the grain is fine per-pixel noise (from #440).
- Card shadows are cut out under the card like a CSS box-shadow; Full effects cards use the
  same Core Animation layers with the glass-regular gradient on the CSS gradient line, and
  the dark Full-effects frame is --glass-border/0.08 as in the cascade.
- Ticker starts active (it never fetched quotes before the scroll view reported it), natural
  tile widths, edge fade mask, liquid-glass box, hover pauses only the tape, and an empty
  provider id falls back to the symbol as in the model.
- fullEffects reads the ADR-255 auto/on/off value; auto is on for the chosen Standard tier.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
…cus and report controls

UI audit batch 3: S-06, S-07, S-08, S-65, S-66 and K4 system-colour leaks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
…ialog height and sankey header

UI audit batch 3: S-36, S-40, S-41, S-68, S-88, S-89 (tile order).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
UI audit batch 3: S-107 (Vision mark, product name, external-link icons).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
…y inventory

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
… compact amounts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
…s and badges

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
…ropdowns

VisionMenu gains checkbox and radio items (Toggle) and VisionMenuLabel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
The hovered arc grows 4.5 % over 0.42 s out-expo and the centre swaps through a
0.15 s fade out then a 0.15 s fade and scale in; nothing moves under Reduce Motion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
…ools

Outline pill with elevation-2, monospaced footnote and hover/open colours; opaque
card panel with border and elevation-4, underline tabs, ghost icon buttons, theme
method colours. The Queries tab stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
… SVG

The chart-wide tracker tested node rectangles first and lit a node's whole
section from the band beside it. Each bar and band now tracks its own hover,
bars drawn over bands, labels take no pointer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
Traffic lights at Electron's trafficLightPosition (20, 20), the 56 pt h-14
topbar with a ghost h-7 sidebar trigger on that centre line, the .app-topbar
veil (gradient, border, highlight, shadow, glide fade), and no system
scroll-edge band under the titlebar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018QJtaMPi3Hb3LQWjLZBk1B
@EraPartner
EraPartner marked this pull request as ready for review November 14, 2026 12:08
@EraPartner
EraPartner merged commit 1e20e0c into main Nov 14, 2026
11 checks passed
@EraPartner
EraPartner deleted the claude/project-thread-eaczlm branch November 14, 2026 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants