iOS postbuild font/scheme cleanup + favicon swap#1
Merged
Conversation
Ensure Capacitor builds remain self-contained by stripping Google Fonts links from iOS output, and remove the duplicate shared Xcode scheme.
Consolidate Stargazer into one prominent Sky control with aligned keyboard/a11y hints, and reduce the initial deep-space cinematic linger so zoom-in starts sooner.
Position top controls with safe-area insets for iOS; enable Sky mode when cinematic lands on Earth; show a dismissible once-per-install intro modal with tour tips and how to turn Sky mode off.
Remove the once-per-install Sky intro sheet; keep a short post-exit hint only. Hide drawer/planet/NEO HUD while cinematic; gate Inner Planets constellation pulse and delayed Sky-toggle blink. Sync iOS builds from dist after pull.
Expose window.__ORRERY_BUILD_STAMP__ so Safari Web Inspector can prove which build is running. Send no-store on dev/preview. Note: pnpm build:ios overwrites dist.
Regenerate the app branding with a constellation plus sun/planet motif and track iOS asset-catalog PNGs so the new visuals ship with the branch.
Add a complete App Store metadata and submission runbook set for the iOS launch so store prep is repeatable and aligned with the current Capacitor workflow.
Update the shipped icon artwork, anchor sidebar controls to safe-area insets on iPad, and decouple Deep Sky from Deep Space while disabling the Milky Way backdrop streak source.
Remove the Milky Way runtime/prefetch path to eliminate iPad startup streak artifacts, tighten iPad panel close behavior, and update launch docs to reflect the current deep-sky/deep-space and QA expectations.
Mobile users could not reach Asterisms or Satellites — the layers filter hid both keys behind a desktop-only check while the help panel still advertised them. The mobile "More" accordion duplicated the desktop Theme picker with a separate 24px-circle control that fell below HIG 44pt and dropped the radio role. - Add Asterisms (A) and Satellites (I) to the layer arrays; remove the mobile filter at Panels.tsx so the full Layers list is reachable on touch. Destructure the missing showAsterisms/showSatellites props. - Delete the mobile-only "More" accordion. Theme + Settings + NEO + Info panels now render on both modes. Unguard the Status accordion so mobile keeps the Moon/View/Rate/Solar Wind stats. - Extract the About overlay into an AboutDialog component with role="dialog", aria-modal, aria-labelledby, focus restoration, Escape key handling, and a Tab/Shift-Tab focus trap. Close button now meets the 44pt minimum. - Theme picker rows are 44pt on both mobile and desktop, with 14px swatches (was 12px) — eliminates the duplicate 24px-circle picker. - Unify the accent-border alpha for active states to 0.3 (was 0.25 and 0.35). - Replace the stale scrollbar selectors in index.css that targeted non-existent aria-labels with the actual "Display layers" and "Celestial bodies" labels.
Followup to the mobile-parity pass. The Panels module had drifted into
half a dozen ad-hoc style vocabularies for the same things: 21 distinct
blur values, 11 z-indices with no rationale (Sky toggle silently sat
under the drawer), close-X buttons reinvented at every call site,
accordion headers split into two components with different fonts and
chevron behavior, and the right-edge chrome offset by 4px between
neighbouring elements.
Tokens (src/ui/styles.ts):
- Z (canvasOverlay/hud/mobileNav/controls/drawer/drawerTab/dialog/modal/loading)
- BLUR (chip/card/drawer/modal/bokeh)
- ALPHA + ACTIVE_ALPHA + TIMING reserved for future sweeps
Sweeps and consolidations:
- Replace every inline zIndex in Panels with a Z member; only the
drawer's local close-button stacking (zIndex 1) remains.
- Replace every inline blur(Npx) with BLUR.chip; drawer-tab was 14px
for no reason — now matches the rest of the chip family.
- Drop the duplicate close-X implementations: InfoPanel close and
SideDrawer close now use the existing Btn helper.
- MiniAccordion takes an accent prop and transitions its chevron color
to match AccordionSection.
- Drawer right edge, drawer-tab, Zoom controls, and Sky toggle all
share safeAreaRight(14); recent iPad-chrome commit had aligned only
half of these.
Sky toggle (src/ui/Panels.tsx):
- Now sits at Z.controls and shifts left to safeAreaRight(340) when
the drawer is open on desktop, so it no longer disappears behind
the panel.
Theme bootstrap (index.html):
- Inline <script> in <head> reads localStorage('orrery-theme') and sets
--accent / --accent-rgb / --panel-border on :root before React mounts.
Drops the var(--accent, #00ffcc) and var(--accent-rgb, 0,255,204)
fallbacks from index.css since the script always sets a value, even
in private browsing (falls through to Brass).
Stale-text cleanup:
- Remove "Milky Way" from OBSERVATORY_STATS — commit 6719301
hard-disabled the runtime backdrop but the loading-screen text stuck.
- SCALE_LANDMARKS "Stellar" moved from distance 20000 to 200000 so it
renders at the top of the ladder instead of 86% up.
iOS bundle:
- B10 (font gate) was a false alarm: scripts/postbuild-ios-html.mjs
already strips the Google Fonts links from dist/index.html for iOS.
- B8 (zoom -> --panel-font-scale) deferred. The CSS-var migration
would require sweeping every font-size in the drawer; left for a
Tier C pass. The zoom hack works in WebKit (iOS) and Chromium;
Firefox web users get default font size, no crash.
Pre-existing react-hooks lint error at the canHover effect is
unchanged and predates this branch.
Two follow-ups from real-device screenshots: Mobile preset strip — INNER/SYSTEM/OUTER/OORT — was 30pt tall with 3px radius and tiny 10px text. Sat right next to the 44pt Sky toggle and looked like a separate design language. Bumped to 44pt height, 6px radius, 12px text with letter-spacing, accent-bg on active using ACTIVE_ALPHA tokens, blur via BLUR.chip. Now matches Sky's chip recipe. Top inset 14 (was 32) to free vertical space; Sky toggle stays at top 84 mobile so they don't collide. Side drawer (desktop) gained a defensive width clamp: - minWidth: 320 (was implicit) - maxWidth: calc(100vw - 28px) — drawer can't exceed viewport - boxSizing: border-box — paddings don't push width past 320 - borderLeft: none — clears the stale borderLeft from drawerPanel base that was a holdover from the flush-right design One screenshot showed the drawer clipped to ~30px wide on iPad landscape with a planet selected. Couldn't reproduce in code paths; the same screenshot's Layers list lacked Asterisms and Satellites, which my Tier A1 commit added — so the screenshot predated my commits reaching the simulator. Defensive clamps land regardless.
Three bugs from real-device iPhone 14 Plus landscape screenshot:
1. Side drawer was clipped to ~50px on the right edge — only the first
2-3 characters of each accordion header visible. Root cause: the
`zoom: panelFontScale` non-standard CSS property interacts badly
with `position: fixed; right: 14; width: 320` under WKWebView,
pushing the drawer hundreds of pixels past the viewport. Replaced
with `fontSize: ${13 * panelFontScale}px` on the drawer container,
which sets the inherited default but does not break layout. Inner
accordion text still uses explicit pixel sizes, so the font-scale
feature is partially regressed for those values — but the panel
renders correctly. Full em-unit migration deferred to Tier C.
2. Drawer tab (sliders pull-handle, right edge center) was rendering
alongside the open drawer, looking like a misplaced second element.
Now hidden when `panelVisible` — the close-X inside the drawer is
the close affordance when the drawer is open.
3. Zoom +/- buttons dispatched a single wheel tick (delta 120) which
barely moved the camera. Now they jump between scale-level camera
presets: Sun → Inner → System → Outer → Kuiper → Oort → Stellar.
The current level is computed by finding the preset whose distance
is logarithmically closest to the current camera distance; +/-
walks one preset in each direction. Buttons disable at the ends.
Deleted ~1100 lines of side-drawer chrome at the user's request. What
remains is the minimum needed to explore the scene:
- Sky toggle button — switches solar-system view ↔ observatory mode
- +/- zoom controls — jumps between scale-level presets (Sun, Inner,
System, Outer, Kuiper, Oort, Stellar)
- Info button + AboutDialog — credits, data sources, links
- Click any stellar object — floating bokehCard with the data we have:
* Sun, planets, moons, dwarfs → distance, period, surface temp,
gravity, moons (existing planet card)
* Constellation → name, season, mythology, notable objects
* Asterism → name, star count, description
* Deep sky → name, type, magnitude, catalog id
* Spacecraft → name, status, launch year, distance, speed
* NEO → live JPL/NASA orbital params (existing)
- Cinematic intro tour on first load
Removed:
- SideDrawer component (~1100 lines, the whole accordion stack)
- Drawer pull-tab
- ScaleIndicator (left-edge Inner/Outer/Kuiper/Oort/Stellar labels)
- Mobile preset strip (INNER/SYSTEM/OUTER/OORT chips)
- AccordionSection, MiniAccordion, SectionHeader, BodyTreeItem,
TonightsSky helpers
- panelPeek / panelNudge / canHover hover-behavior infrastructure
- panelFontScale + custom-event plumbing (settings UI is gone;
state still accepted as prop but unused)
Tokens kept (still useful for any new chrome):
- bokehCard — used by every floating info card
- Z (canvasOverlay/hud/controls/dialog/modal/loading) — stripped
unused drawer/drawerTab/mobileNav layers
- BLUR, ALPHA, ACTIVE_ALPHA, TIMING — semantic constants stand
Layer state machinery (showStars, showConstellations, showAsterisms,
etc.) is still threaded as props so Sky toggle and keyboard
shortcuts work as before. Power users can still toggle individual
layers via keys (S/L/A/K/O/D/N/C/R/I/M). Touch users get an
all-on default until we add a settings affordance back.
The InfoPanel component was rewritten to render as a floating
bokehCard at bottom (mobile) or bottom-right (desktop), with a
section-tag header and a 44pt close-X via the Btn helper.
src/ui/Panels.tsx: 1872 → 879 lines (−993).
src/ui/styles.ts: 138 → 79 lines (−59).
Align Sky mode with compact corner controls, add persistent zoom buttons, and condense the planet info card so mobile and desktop overlays use space more efficiently. Strengthen immersive sky rendering by boosting star/deep-sky emphasis and dimming only when Sky mode is off or a single constellation is selected.
Unify Sky mode entry behavior across keyboard and button interactions, improve HUD accessibility with larger touch targets and safe-area anchoring, and prevent zoom overlay hit-area collisions with the canvas. Tighten keyboard semantics for details and breadcrumb navigation to keep overlay interactions consistent.
- Move Sky toggle to upper-right with inline constellation SVG; keep info (i) upper-left; preserve area labels and pulse behavior. - Replace About dialog text Close with icon-style x and surface linked catalog/live data sources. - Add billboard pick proxies for spacecraft, nearby stars, and Local Group galaxies; thread selections through Orrery/Scene/Panels with non-overlapping left/right info-card placement. - Make Sol selectable via enlarged invisible tap target; allow moon picks across all parents. - Replace random R button with dice-icon toggle that runs an ongoing tour over presets, planets, moons, constellations, spacecraft, nearby stars, and galaxies (~7s cadence). Double-click triggers a single jump; cinematic mode auto-stops the tour.
…e next to sky toggle - Add `src/lib/constellationCentroids.ts` to fetch and cache constellation Point features from `public/data/constellations.json`. Average duplicate ids (e.g. Serpens Caput + Cauda for `Ser`) via 3D Cartesian midpoint then renormalise to avoid Map.set overwriting one half with the other. - Add `aimAtSphere` prop to `CamCtrl` in `Scene.tsx`. When set, the camera lerps to a vantage 8 units inside the celestial sphere along the line origin -> target so the user actually faces the rolled constellation. - Wire `aimAtSphere` through `Orrery.tsx`. Cleared on planet/moon/sun/preset selection, Sky-mode `g` entry, escape and pointer-missed in observatory, and at cinematic enter/exit. The latter also invalidates `lastTourPickRef` so a slow constellation Promise resolving after cinematic exit can no longer pull the camera to a stale aim. - Move the dice button out of the zoom column and into the top-right HUD cluster next to the Sky toggle. Single click triggers an immediate transition; works mid-flight (no toggle, no interval).
…oint centroids
Address review findings on the random-tour dice button:
- Drop M045 (Pleiades) from FAMOUS_DSO. `prebake-deepsky.ts` filters it out of
`public/data/deepsky.json` via NGC mag/size cutoffs, so the info card was
silently failing to resolve on ~10% of DSO rolls.
- Add a `name` field to FAMOUS_DSO and use it in the breadcrumb. The previous
nav stack showed the catalog id ("M042") instead of the friendly name.
- Enable `showDwarf` when a dwarf-planet index (>=8) is rolled. Without this
Eris/Pluto/Ceres are filtered out of `visibleBodies` and the camera lands in
empty space at the right coordinates with no body to focus.
- Move FAMOUS_DSO + CELESTIAL_SPHERE_RADIUS below the import block so module
imports stay contiguous.
- Add a 'Deep Sky' branch to currentAreaLabel so the scale label matches the
active selection instead of falling through to 'Full System'.
Also folds in the previously uncommitted constellation-centroid and mobile
zoom-control improvements:
- Centroid math now prefers averaging line-endpoints from
`constellations.lines.json` over the Point features (which are label
positions, often offset for legibility). The 3D Cartesian average handles
the RA 0/360 wrap and multi-segment figures (Serpens) in one pass.
- Mobile zoom column repositioned to safeAreaTop(64) at z-index Z.hud so the
+/- buttons sit directly under the dice/sky chip cluster.
…Earth landing The cinematic tour was strobing constellations on/off mid-flight: Deep Space turned them on, Solar System back off, Inner Planets on with a tour-pulse shimmer, Earth focus off again, and exit-on-Earth turned them on once more. Three transitions in five seconds is visual noise. Now Deep Space, Solar System and Inner Planets all leave constellations off, and `exitCinematic` (Earth landing) is the single moment they appear, paired with the existing `constellationRevealTick` fade-in and the Sky-toggle pulse. Removes the now-dead pulse machinery: `constellationTourPulse` state, the `innerPlanetsPulseTimerRef` timer ref + cleanup, and `constellationPulseUntilRef` (the Sky-toggle wait collapses to a fixed 200ms grace). Drops the `constellationTourPulse` prop wiring through Scene.tsx. ConstellationLines/Labels still accept the optional prop with a default of false, so future use is unaffected.
…hlight
Three regressions stacked on top of each other made objects feel un-clickable
and showed iOS tap highlights everywhere. Root causes were independent.
- src/scene/Stars.tsx: every visible constellation label was wrapped in a
210x180 invisible click box (minWidth/minHeight defaulted on, only the
zodiac-glyph focus mode actually needed the room). Across the celestial
sphere this layered hundreds of giant DOM hit zones over the canvas, eating
taps on planets/moons that happened to project behind them and triggering
the iOS tap highlight on every miss. Now the box only enforces minWidth /
minHeight when a zodiac glyph is rendered; otherwise the label auto-sizes
to the text and the alignment falls back to centered.
- src/scene/DeepSpace.tsx: spacecraft / nearby-star / galaxy pick proxies
used `<meshBasicMaterial transparent opacity={0} depthWrite={false}/>`,
which still renders to the alpha buffer. Switched to `visible={false}`,
matching the planet/moon hit-target pattern in Bodies.tsx — the geometry
still raycasts but writes zero pixels.
- src/index.css: explicit `-webkit-tap-highlight-color: transparent` on the
page and on `<canvas>` so iOS WebKit no longer flashes its default gray
rectangle on every tap.
Random tour: cap constellations to a curated list of 8 iconic figures (Orion,
Ursa Major, Cassiopeia, Cygnus, Leo, Scorpius, Taurus, Crux). Drawing
uniformly from the full 88-IAU bag had constellations winning ~60% of dice
rolls and drowning out planets / DSO / spacecraft / moons / presets. With
the cap they're now ~12% of rolls.
iPad/desktop placement at bottom-right was occluded by the InfoPanel detail card, which pins itself to [bottom: 16, right: 16] with full-height width whenever a planet/constellation/DSO is selected. The +/- buttons disappeared behind it the moment any object was tapped. Drop the mobile-vs-desktop branch and always render the zoom column directly under the dice/sky chip cluster at top-right (the placement phones already used). Removes the now-dead `mobile` prop on ZoomControls.
Improve distant planet selection by enforcing a minimum on-screen pick radius, so clicks near far planets (e.g. Jupiter while focused on Ceres) register reliably.
Clamp distance-scaled planet pick proxies so they never envelop the camera at close zoom levels, while keeping distant planets easy to select. Rework the planet facts card into a denser 6-item grid with period and gravity normalized to Earth-relative units and distance deprioritized.
Camera + jitter (M0–M1): - Extract CamCtrl from Scene.tsx with phased state machine (idle / settling / tracking / cinematic / observing / aiming) - Memoize positions on T to stop per-frame Map churn; throttle parent notify to centennial-fraction T deltas - Init prevTrackPos at settle to kill first-frame post-settle kick - Dice sky targets (constellations / DSOs) skip Stargazer staging; single intent fires per click - Camera near 0.005 → 0.02 to relieve WebKit logarithmicDepthBuffer - Mobile star catalog (mag ≤ 6.5, ~9K stars) loaded via useIsMobile - prebake-stars.ts now writes both desktop and mobile catalogs Reliability (M3): - LoadingScreen 8s watchdog with 2 retries + Reload affordance - webglcontextlost / restored handlers re-mount Canvas and reset tasks - Per-feature Suspense boundaries in Scene.tsx so one failing fetch no longer blanks the entire scene - visibilitychange pauses sim tick + cinematic poll; resumes cleanly - CelesTrak TLE first, bundled stations.tle as fallback only - prebake-tle.ts refreshes stations.tle in the prebake pipeline - VITE_NEO_FEED_URL / VITE_NASA_API_KEY env support; .env.example - Cinematic exits gracefully on user OrbitControls drag - Bodies.tsx textures reactive via useIsMobile() (fixes iPad rotation) - mw.json (524 KB unused) removed from public/data/ - neoStatus='error' surfaces as in-app banner App Store (M2): - public/privacy.html enumerating all third-party fetches - About dialog adds Licenses section + Privacy policy link (CC BY-SA / CC BY / BSD-3 attribution required by upstreams) - LICENSE re-scoped to source code; THIRD_PARTY_NOTICES.md added - NEO synthetic orbit flagged in lib/kepler.ts and shown as "Approximate orbit — JPL SBDB unavailable" in info card - app-store/REJECTION_NOTES.md template for Resolution Center Architecture (M4): - Cinematic steps reference preset labels via camIndex(), not array indices — reordering CAMS no longer silently breaks the tour - CAM_PRESET_LAYER_EFFECTS map replaces inline preset side-effect cascade in handlePresetSelect Tests + CI (M5): - Vitest setup with 15 tests: kepler golden vectors (Earth/Mars/Jupiter ±0.005 AU) CAMS label-order integrity, observe-mode preset contract raDecTo3D round-trip, mode URL contract, iOS font-strip regex - GitHub Actions CI runs lint + test + build on push and PR Diagnostics: - __ORRERY_DIAG__ overlay (window flag or localStorage orrery-diag=1) shows FPS, R/s, camera distance, settling phase, positions Δ/s
Snap ctrl.target to the look point on every target change (focus, preset, aim-at-sphere) so the camera orients to its destination immediately, then make subsequent look-at lerp 5x faster than the position lerp. Cinematography rule: orient first, dolly second. Before: posAlpha and lookAlpha were nearly identical, so for distant dice rolls (constellations, DSOs at ~292 AU) the camera would slide toward the target with the destination still off-frame, only catching up to actually look at it once nearly arrived. After: camera whips to face the destination instantly, then drifts into position with the target stably centered the entire travel.
…destinations Telemetry showed dice rolls landing the camera in empty space for these categories: their rendering scheme (camera-pinned celestial sphere or fixed beyond any preset's reach) doesn't agree with the dice's "fly toward target" model. The fix: * Strip dso, nearStar, galaxy, spacecraft from the dice destination pool. * Remove the DeepSky data layer entirely (Field component, deepsky.json, prebake-deepsky.ts, preload tag, About-dialog mention, layer toggle, and selDeepSky state) — sphere-pinned shader points are unreadable at any alpha when you can't fly closer. * Remove the broken "Jump to Oort/Stellar view" buttons from the spacecraft / nearby-star / galaxy info cards (they jumped to presets that framed empty space, not the object). * Keep DeepSpace + spacecraft + nearby-star + galaxy layers as decoration — still toggleable, still selectable via direct click, just not destinations. * Document the long-term Stellar Neighborhood Mode in PROJECT_PLAN.md (de-pin selected stars, render real solar-analog suns at fixed cosmic position, switch the camera coordinate system) as the right way to make "fly to Sirius" feel like a destination. Lint, vitest, and pnpm build all green; bundle saved 35 KB on the deleted catalog.
…s layer toggles Constellation rolls had a one-frame flash where CamCtrl rendered with focusTarget/camPreset/aimAtSphere all null and snapped the camera target to the origin (Sun) before the async getConstellationCentroid promise resolved and re-snapped to the centroid. Visible as a target whip toward the Sun and then back out to the constellation. Expose getConstellationCentroidCached as a sync lookup against the cache already warmed by prefetchConstellationCentroids on mount. Dice path uses it first and falls back to the async path (with the existing aimTicket staleness gate) on cache miss, so the first dice roll after a cold start still works correctly if the prefetch hasn't completed yet. Audited the dice pool at the same time: confirmed it contains only solar-system targets (6 presets, 8 planets, 3 dwarfs, up to 8 moons) plus the 8 famous constellations from FAMOUS_CONSTELLATIONS. No galaxies, near-stars, spacecraft, or DSOs — those were already cut by 43602cf and 753f3a9.
…ates Snapshot of in-flight work; committed on the existing working branch, main untouched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The cursor working branch from beast (last commits 2026-05-21 plus the favicon svg-to-png swap committed during the 2026-06-09 audit). Main is ~3 weeks behind this branch. Orrery is live and working, so merge deliberately - nothing here is deployed until merged and pulled.