krz/moonrise

Night-sky companion for iPhone, Apple Watch and Vision Pro: what's up tonight, the Moon, planets, launches and missions, and a Library of the solar system. SwiftUI app with a Cloudflare Workers backend. astronomy cloudflare-workers ios night-sky space swiftui visionos watchos

PLAN.org

04b2b1d914788057bcd20945b876847386eb8f65
moonrise/PLAN.org rendered · source · history · blame · raw

450 lines · 23259 bytes

36 symbols in this file
  1#+title: Moonrise
  2#+subtitle: concept and plan
  3
  4* name
  5*Moonrise.* App Store name with a descriptor, e.g. "Moonrise: Sky and
  6Space", since the bare name is shared and reads as moon-only.
  7
  8Existing apps (Oct 2026 search), all moon-times utilities: AVIA Moonrise
  9(id390606204, last updated 2021), Moonrise Moment (id6788237210),
 10Mooncaster. The descriptor and screenshots need to show the app covers
 11far more than the moon.
 12
 13Reserved in App Store Connect 2026-10-17. USPTO search not done.
 14
 15* Apple identifiers
 16| Item | Value |
 17|-
 18| Team ID | =ZCNAX3VL9D= |
 19| Bundle ID | =sh.krz.moonrise= |
 20| APNs key | "Moonrise APNs", key ID =644XS4F2RG=, Sandbox and Production. The .p8 is held outside the repo. |
 21
 22* concept
 23An iPhone app for everything in space: what is overhead tonight, what the
 24sun is doing, what is launching, where our spacecraft are, and a
 25reference library for the planets, stars, galaxies and missions.
 26
 27The lead on every tab is a picture computed from real data or a real
 28image: the sky above you, the solar system today, the sun this hour, a
 29rocket on its pad. Text sits underneath, a swipe or tap away.
 30
 31Free of accounts. Works offline for anything that can be computed;
 32fetches only live feeds.
 33
 34* design
 35After NASA's 1975 Graphics Standards Manual.
 36
 37- Helvetica Neue (ships with iOS). Tabular figures for all numbers.
 38- Strict grid, flush left, black hairlines, numbered modules.
 39- Off-white and ink by day. Near-black with white line work at night.
 40- One red accent for alerts and emphasis. Not NASA's exact red, no NASA
 41  insignia or worm logotype, nothing that reads as an official NASA app.
 42- Drawings are technical: orbits as orbits, dimension lines, to-scale
 43  comparisons, Gantt-style mission timelines.
 44- Night mode: red-on-black for dark-adapted eyes, switched on
 45  automatically after astronomical dusk while the Sky tab is open.
 46- Motion only where it carries data: planets moving at true relative
 47  speeds, the moon's phase easing while scrubbing time.
 48
 49Avoid: neon on black, glow, scan lines, hexagons, crosshairs,
 50monospaced readouts as decoration.
 51
 52* screens
 53Five tabs.
 54
 55** 1. Sky (home)
 56- Full-screen sky for your location and time: horizon, stars to about
 57  magnitude 6, constellation lines, planets, the moon at its true phase,
 58  the sun below the horizon as a glow at the edge.
 59- Pans with the device (compass and gyroscope) or by drag. Pinch to zoom.
 60- Tap any object for a card: name, magnitude, rise and set, distance,
 61  link to its Library page.
 62- Time scrubber: drag hours forward or back; tap to return to now.
 63- Alert chips across the top when relevant: aurora (Kp threshold for
 64  your latitude), ISS pass within the hour, launch within the hour,
 65  eclipse or conjunction today.
 66- Today sheet, pulled up from the bottom:
 67  - Moon: phase, illumination, next quarter.
 68  - Visible tonight: planets with direction, altitude, rise and set.
 69  - ISS passes over the next 3 days.
 70  - Next launch with countdown.
 71  - Space weather: Kp now and forecast.
 72  - Deep space: Voyager 1 distance and light time.
 73
 74** 2. System
 75- Top-down orrery of the solar system for today. Log-scaled distances by
 76  default; toggle to true scale.
 77- Time slider from 1957 to 2050. Planets and spacecraft move together.
 78- Spacecraft drawn with their trajectories: Voyager 1 and 2, New
 79  Horizons, Juno, Europa Clipper, JUICE, Psyche, Parker Solar Probe,
 80  Lucy, and missions at Mars.
 81- Tap a planet or spacecraft for its Library page.
 82- Inset for Earth–Moon space: ISS, JWST at L2, lunar missions.
 83
 84** 3. Sun
 85- Latest SDO full-disk image, full width. Swipe between wavelengths:
 86  171 Å (corona), 304 Å (chromosphere), 193 Å, HMI visible light.
 87- Kp index: bar chart for the last 3 days and the 3-day forecast.
 88- Aurora oval for your hemisphere (OVATION model) with your location
 89  marked.
 90- Solar flares: GOES X-ray flux for the last 24 hours, flare classes
 91  marked.
 92- Plain-language summary in one line: "Quiet", "Minor storm likely
 93  tonight", and similar.
 94
 95** 4. Launches
 96- Upcoming launches, each led by the rocket's silhouette drawn to a
 97  common scale.
 98- Detail: vehicle, mission, payload, orbit, pad on a map, countdown,
 99  launch window, webcast link.
100- Live Activity from T−1 hour through orbit insertion.
101- Past launches with outcome.
102
103** 5. Library
104Every page leads with a drawing or image; facts follow as a spec sheet.
105
106- Solar system: the sun, 8 planets, dwarf planets, major moons. Each has
107  a dimensioned drawing, a to-scale comparison with Earth, a facts grid,
108  the missions that visited on a timeline, and a short essay.
109- Constellations: all 88. Modern line figure, the plate from a
110  historical atlas (Bayer, Hevelius, Bode), bright stars, best season,
111  where it is tonight.
112- Stars: bright named stars with type, distance, colour and the origin
113  of the name.
114- Deep sky: the 110 Messier objects, then well-known NGC objects, with
115  Hubble, Webb or ground images and a scale bar.
116- Spacecraft and missions: active and historic. Status, location,
117  instruments, findings, timeline.
118- Later sections: exoplanets, rockets side by side to scale, the history
119  of exploration as a browsable timeline, a scale view from Earth to the
120  observable universe.
121
122Search across all of it from the Library tab.
123
124* widgets, Live Activities, notifications
125- Lock Screen: moon phase; Kp; next launch countdown.
126- Home Screen: tonight's planets; Voyager 1 distance; today's sun image.
127- Live Activity: launch countdown through orbit.
128- Notifications, each off by default and opt-in: aurora possible at your
129  latitude; launch in one hour; ISS visible pass in 15 minutes.
130
131* data sources
132Checked 2026-10-17 against primary sources unless marked unconfirmed.
133
134| Source | Use | Terms and limits |
135|-
136| Astronomy Engine v2.1.19 (Don Cross) | Sun, moon, planet positions; rise, set, phases, eclipses, conjunctions | MIT, keep notice. No Swift package; C source vendored as an SPM target. Last release 2023-12. |
137| Yale Bright Star Catalogue (VizieR V/50) | 9,096 stars with V mag, bundled | No licence in ReadMe; VizieR says "free in a scientific context", check per catalogue. US-government origin (NSSDC); public domain unconfirmed. |
138| HYG database | Star names, distances | CC BY-SA 4.0; use only if BSC5 is not enough |
139| IAU boundaries (VizieR VI/49) | Boundaries | Same VizieR ambiguity as BSC5 |
140| Constellation lines: van der Sluys ConstellationLines v1.4 | Stick figures by HR number, bundled | CC BY 4.0. Credit: "Constellation lines: Marc van der Sluys, ConstellationLines (doi:10.5281/zenodo.10397192), CC BY 4.0." Stellarium (CC BY-SA, AGPL repo) and d3-celestial (no data licence) rejected. |
141| OpenNGC | Messier and NGC object data | CC BY-SA 4.0; ShareAlike on the data file. Decide before M5. |
142| NOAA SWPC JSON | Kp (=json/planetary_k_index_1m.json=), Kp forecast (=products/noaa-planetary-k-index-forecast.json=, array of objects), OVATION (=json/ovation_aurora_latest.json=, ~900 KB), GOES X-ray (=json/goes/primary/xrays-6-hour.json=), alerts (=products/alerts.json=) | No terms page; US government. =cache-control: max-age=60=: poll at most once a minute. |
143| NASA SDO | =assets/img/latest/latest_{512,1024,...}_{0171,0193,0304,HMIIC}.jpg= | Not copyrighted unless noted. Credit: "Courtesy of NASA/SDO and the AIA, EVE, and HMI science teams." |
144| JPL Horizons API | Spacecraft positions (Voyager 1 = -31) | No published limit; errors come back as HTTP 200, check payload. Cache server-side. |
145| CelesTrak GP | =celestrak.org/NORAD/elements/gp.php?CATNR=25544&FORMAT=JSON= | Updates every 2 h; one download per update. >50 HTTP errors in 2 h blocks the IP. Fetch only from the Worker; stop on any non-200. |
146| Launch Library 2 v2.3.0 | =ll.thespacedevs.com/2.3.0/= | 15 requests/hour anonymous (confirmed). Higher tiers via Patreon; price, commercial and attribution terms unpublished. Ask The Space Devs before launch. |
147| NASA Image and Video Library | Planet, mission and spacecraft images | Generally not copyrighted; acknowledge NASA. Insignia and logotype protected; no implied endorsement; no current astronauts in promotion. |
148| ESA/Hubble, ESA/Webb, ESO | Deep-sky images | CC BY 4.0; full credit line visible next to each image; note modifications. ESO: no commercial use of identifiable people. |
149| USGS Astrogeology | Planet and moon maps | Public domain |
150| NASA Exoplanet Archive | Exoplanets (later) | Public; bundle a snapshot, refresh periodically |
151| Historical star atlases (LoC, Linda Hall Library, Wikimedia scans) | Constellation plates | Works public domain; check each scan's terms |
152
153Track source and licence per image in the content bundle from day one.
154
155* architecture
156- iOS 26+, SwiftUI, Swift 6 language mode. iPhone first; iPad layout in
157  v1.1.
158- Packages:
159  - =SkyEngine=: Swift wrapper over Astronomy Engine's C library.
160    Coordinates, rise and set, phases, events, kō-style solar longitude
161    (shared with the parked seventy-two app).
162  - =SkyRenderer=: SwiftUI Canvas first; move to Metal if 9,000 stars
163    plus lines cannot hold 60 fps while panning.
164  - =Feeds=: typed clients for SWPC, SDO, CelesTrak, the backend. Cached
165    on disk with per-feed lifetimes.
166  - =Library=: bundled content (JSON plus images), versioned, updatable
167    from the backend without an app release.
168- Backend on Cloudflare; see [[*backend][backend]].
169- No accounts. Device registers an APNs token and a coarse latitude band
170  for aurora alerts, nothing else.
171
172* backend
173Only what the app cannot do alone: cache rate-limited feeds (Launch
174Library 2, Horizons), send pushes (aurora, launches), drive launch Live
175Activities, ship Library content updates. Positions, phases and ISS passes
176are computed on device; ISS pass alerts are local notifications. SWPC and
177SDO are public, so the app can fetch them directly if the backend is down.
178
179** Cloudflare products
180| Product | Role |
181|-
182| Workers (TypeScript) | JSON API; APNs sender |
183| Cron Triggers | Feed polling |
184| D1 | Devices, launches, alert dedupe, Live Activity tokens, ephemeris, content versions |
185| Workers Cache | Cache GET responses (=/v1/today= etc.) |
186| Queues | Push fan-out with retries, decoupled from polling |
187| R2 | Library content packs, widget-sized SDO thumbnails |
188| Workers secrets | APNs .p8 key, key ID, team ID; Launch Library 2 key |
189| Workers Rate Limiting | Per-IP limits on device registration |
190
191** APNs from Workers
192APNs requires HTTP/2. A Cloudflare engineer stated in workerd issue #4841
193(2025-08-20) that production requests pass through Cloudflare's proxy,
194which upgrades them to HTTP/2; workerd itself, and so =wrangler dev=, does
195not support HTTP/2 and there are no plans to add it. Cloudflare's docs do
196not state this. Open-source senders rely on it (e.g.
197FiveSheepCo/cloudflare-apns2). Containers (Workers Paid) can run an HTTP/2
198sender as a fallback. Spike: =spikes/apns-worker=.
199
200- Sign the ES256 provider JWT with WebCrypto; reuse it for 20–60 minutes
201  as Apple requires.
202- Test pushes against a deployed staging Worker using the sandbox APNs
203  host, never from local dev.
204- Keep the sender behind the push Queue so it can move to Cloudflare
205  Containers (a small Go or Python sender) if Workers' HTTP/2 stops
206  working, without touching the rest.
207- Delete tokens on HTTP 410.
208
209** jobs
210| Cron | Job |
211|-
212| =*/5 * * * *= | SWPC: 1-minute Kp, Kp forecast, OVATION aurora, alerts; run aurora engine |
213| =*/10 * * * *= | Launch Library 2 upcoming list |
214| =* * * * *= | If a launch is within 1 h: poll it (needs paid LL2 key); push Live Activity updates on status change |
215| =0 */4 * * *= | CelesTrak ISS and bright satellites |
216| =15 3 * * *= | JPL Horizons daily positions for ~20 spacecraft |
217
218The anonymous Launch Library 2 tier is 15 requests/hour; the 1-minute job
219needs a key. CelesTrak: never more than once per 2-hour update.
220
221** data (D1)
222- =devices=: APNs token, environment (sandbox/production), 5°
223  geomagnetic latitude band, UTC offset, preferences (aurora threshold,
224  launch alerts, quiet hours), last seen.
225- =launches=: normalized LL2 cache plus raw JSON.
226- =feed_snapshots=: latest result per feed with fetch time and status.
227- =alerts_sent=: dedupe key (type, band, storm event).
228- =live_activity_tokens=: launch, update token, device; push-to-start
229  tokens separately.
230- =spacecraft_ephemeris=: spacecraft, date, position.
231- =content_versions=: pack, version, hash, R2 key.
232
233** API
234| Method and path | Purpose |
235|-
236| =GET /v1/today= | One small payload: next launches, space weather summary, active alerts, spacecraft positions, content version. ETag. |
237| =GET /v1/launches=, =GET /v1/launches/{id}= | List, detail |
238| =GET /v1/spacecraft?ids=&from=&to== | Recent positions; full history ships in the app |
239| =GET /v1/content/manifest=, =GET /v1/content/{pack}= | Library updates from R2 |
240| =POST/PATCH/DELETE /v1/devices[/{token}]= | Register, preferences, unregister |
241| =POST /v1/live-activities= | Register an update token for a launch |
242| =GET /healthz= | Liveness and per-feed staleness |
243
244** alerts
245- Aurora: from Kp forecast and OVATION, find the latitude bands that can
246  see aurora; notify devices in those bands where it is dark, outside
247  quiet hours; at most one per band per storm.
248- Launches: "launch in one hour" to opted-in devices; push-to-start the
249  Live Activity (iOS 17.2+); update on countdown, hold, liftoff, staging,
250  orbit or scrub; end 15 minutes after the outcome.
251
252** privacy and abuse
253- Stored per device: push token, 5° latitude band, UTC offset,
254  preferences. No location, no accounts.
255- v1: per-IP rate limits. Later: App Attest verification in the Worker.
256
257** operations
258- Lives in =server/= in this repo (a separate =moonrise-server= repo is
259  optional); deploy with Wrangler.
260- Staging and production Workers with separate D1 databases and APNs
261  environments.
262- Workers Logs for errors; feed staleness in =/healthz=.
263- Likely Workers Paid plan (about $5/month) plus an optional Launch
264  Library 2 key. Check current pricing for Queues and D1 before launch.
265
266* content
267The Library is the largest piece of work.
268
269- v1: sun, 8 planets, 5 dwarf planets, ~25 major moons, 88
270  constellations, ~50 named stars, 110 Messier objects, ~40 missions.
271  About 320 pages.
272- Write in one voice: short essay plus spec sheet per page. Start from
273  NASA public-domain text where useful, rewritten.
274- Drawings for every planet and moon in the house style, generated from
275  data (radius, oblateness, rings, axial tilt) rather than drawn by hand.
276
277* milestones
278- *M0, spike.* Confirm every source, licence and rate limit above.
279  Astronomy Engine building from Swift with tests against Horizons.
280  Static sky render for one place and time. Reserve the name.
281- *M1, Sky.* Live sky with device motion, object cards, time scrubber,
282  night mode, Today sheet. Moon and planets widgets.
283- *M2, Sun.* SDO images, Kp, aurora oval, flares. Backend up; aurora
284  push.
285- *M3, Launches.* List, detail, rocket silhouettes, Live Activity.
286- *M4, System.* Orrery with time slider and spacecraft trajectories.
287- *M5, Library v1.* Solar system, constellations, stars, Messier,
288  missions. Search.
289- *1.0* = M1–M5, TestFlight, App Store.
290
291** M0 results (2026-10-17)
292- Data sources: checked; see [[*data sources][data sources]]. Open: Launch Library 2
293  commercial terms, OpenNGC ShareAlike, BSC5 licence statement.
294- =Packages/MoonriseKit=:
295  - =CAstronomy=: Astronomy Engine v2.1.19 C source.
296  - =SkyEngine=: Swift wrapper. Tests against JPL Horizons (Chicago,
297    2026-10-17 02:00 UT): apparent RA/Dec and airless alt/az for the Moon,
298    Mars, Jupiter, Saturn within 1′; heliocentric Jupiter and Saturn within
299    1′ angular (Saturn 0.00045 AU, about 10″).
300  - =SkyRenderer=: stereographic projection, 8,404 stars to V 6.5, 88
301    constellations, planets to mag 6, moon with phase, horizon. Scene
302    build 0.03 s, Canvas render of a 1179×2556 frame 0.09 s on an Apple
303    silicon Mac via =ImageRenderer=. Not measured on a device; panning at
304    60 fps (16 ms per frame) is unproven and likely needs culling,
305    pre-rendered star layers or Metal.
306- =spikes/apns-worker=: ES256 provider token via WebCrypto (unit-tested),
307  =/push= and a credential-free =/probe=. Deployed as
308  =moonrise-apns-spike=; =/probe= got APNs JSON responses (403
309  =InvalidProviderToken= with an =apns-id=) on 3 of 3 calls, so the
310  deployed Worker reaches the APNs sandbox over HTTP/2. Worker deleted
311  after the test. A real push still needs an APNs key and a device token.
312- Name reserved in App Store Connect; APNs key created (key ID 644XS4F2RG).
313
314** M1 status (2026-10-17)
315Stacked MRs: !2 app shell, !3 interaction, !4 Today sheet, !5 widgets,
316!6 device pointing.
317
318Done and checked in the iOS 27 simulator: live sky with location, drag
319and pinch, object cards, time scrubber, night mode, Today sheet (moon,
320planets, sun, live SWPC Kp), sandbox APNs token.
321
322Built but not checked:
323- Widgets: build and embed; not viewed (simulator widget gallery could
324  not be driven by automation).
325- Device pointing: maths unit-tested; needs a real phone.
326
327Not done:
328- Draw time on a real iPhone (decides Canvas vs Metal).
329- ISS passes: need an SGP4 propagator and CelesTrak data via the backend.
330- Launches and Voyager in the Today sheet: backend (M2, M3).
331- Automatic night mode after astronomical dusk.
332
333** M2 status (2026-10-17)
334Stacked MRs: !7 Sun tab, !8 backend, !9 aurora map.
335
336- Sun tab: done, checked in the simulator with live data.
337- Backend (=server/=): SWPC polling, =/v1/today=, device registration,
338  aurora alert rules and APNs sending. Unit-tested; smoke-tested under
339  =wrangler dev= with a local D1. Not deployed.
340- Simplifications against the design above: aurora pushes are sent
341  in-line from the cron (no Queue yet); "dark" is 20:00–04:00 local time
342  rather than sun altitude; no rate limiting or App Attest on
343  registration yet.
344- Aurora map: OVATION probabilities on a polar map with Natural Earth
345  coastlines; checked in the simulator.
346- Not done: app registration with the backend (needs a deployed URL),
347  launch caching, Live Activities.
348
349** M3 status (2026-10-17)
350MR !10.
351
352- Backend: Launch Library 2 upcoming list every 10 minutes (separate cron,
353  6 of 15 anonymous requests per hour) into D1; =GET /v1/launches=.
354  Smoke-tested locally with live LL2 data. LL2 images are not used
355  (licence often "Unknown").
356- App: Launches tab (list with T− countdowns, detail sheet); Debug builds
357  read the API from =http://localhost:8787= (=MOONRISE_API_URL=).
358- Live Activity: "Follow on Lock Screen" starts a local countdown
359  activity; verified on the simulator Lock Screen. Updates by push
360  (holds, scrubs, liftoff) not done.
361- Not done: rocket silhouettes to scale, push-to-start and push updates,
362  "launch in one hour" notification.
363
364** M4 status (2026-10-17)
365MR !11.
366
367- System tab: orrery with planets from Astronomy Engine (ecliptic axes),
368  log radial scale beyond 1 AU, Voyager 1 and 2, Pioneer 10 and 11 and New
369  Horizons paths from bundled JPL Horizons vectors (30-day steps to 2050),
370  time slider 1958–2050 with play, distance and light-time table. Checked
371  in the simulator.
372- =SkyEngine= now holds one recursive lock around all Astronomy Engine
373  calls, so any thread can use it.
374- Not done: tap a planet or probe for its Library page, Earth–Moon inset,
375  active missions (Juno, Europa Clipper, JUICE, Psyche, Parker, Lucy).
376
377** Deployment (2026-10-18)
378- Worker =moonrise-server= at https://moonrise-server.audit-labs.workers.dev,
379  D1 =moonrise=, crons =*/5= (SWPC) and =*/10= (LL2), APNS_KEY set.
380- SWPC polling confirmed in production (=/v1/today= serving Kp).
381- LL2 from Cloudflare returned 429 on the first run: the anonymous limit
382  is per IP and Workers share egress IPs. Needs an LL2 API key
383  (=LL2_API_KEY= secret, supported). Launches stay empty until then.
384- App Debug and Release builds use the deployed URL.
385- The app does not register devices with the backend yet, so no aurora
386  pushes are sent.
387
388* roadmap
389** v1: now
390Sky, System, Sun, Launches, Library core (above).
391
392** v2: plan, track, more devices
393- Events: eclipses, meteor showers, conjunctions, oppositions, each with
394  an observing plan. Eclipse path maps with local timings; the 2 August
395  2027 total eclipse (Spain, North Africa, Egypt) is a launch target.
396  Path maps and local timings done for every total and annular eclipse.
397- Deep Space Network Now: which DSN dishes are talking to which
398  spacecraft.
399- More satellites: Tiangong, Hubble, Starlink trains, bright passes. Done:
400  CelesTrak visual group plus one element set per Starlink launch still
401  below about 400 km.
402- Observing log stored as plain text or Org.
403- Mars: latest rover raw images, local time at each rover.
404- Library: exoplanets, rockets to scale, exploration timeline, scale
405  view. Done.
406- iPad, Mac, Apple Watch complications. Done: Mac as "Designed for iPad";
407  Watch app (Moon, Sun, planets tonight) with Moon and Planets complications.
408
409** v3: across time and cultures
410- Sky cultures: Chinese, Polynesian, Arabic, Norse and other
411  constellations over the same stars. Done for the ten CC BY-SA cultures in
412  Stellarium's set; Arabic is not included (CC BY-ND, permission granted only
413  to Stellarium).
414- Historical sky for any date and place, with precession. Done: 3000 BCE
415  to 3000 CE, with BSC5 proper motions and the pole star of the year.
416- 3D planets from USGS maps; immersive sky and orrery on Vision Pro. Done:
417  globes for the Sun, planets, dwarf planets and moons (NASA/USGS maps for 13,
418  colour for the rest); visionOS app with globes, an orrery volume and an
419  immersive star field. visionOS is compiled but not yet run (no simulator
420  runtime installed).
421- Guided seasonal sky tours and mission stories. Tours done: four, by
422  months, 5 to 8 stops each, in Library/Resources/tours. Mission stories
423  done for Voyager 1 and 2, Pioneer 10 and 11 and New Horizons, on the orrery.
424- Live coverage of major events (e.g. an Artemis landing) on the orrery
425  with a Live Activity. Done: GET /v1/live with a Horizons trajectory, an
426  Earth–Moon map on the System tab and a Live Activity. Artemis I is configured
427  as a past event for replay; add Artemis II and later missions to
428  server/src/live.ts (Horizons ID, window, phases) once their Horizons IDs are
429  published.
430- Maybe: smart-telescope pointing (Seestar and similar).
431
432* risks
433- Library scope: 320 pages is most of the effort. Ship 1.0 with fewer
434  pages before adding more.
435- Sky render performance and compass accuracy; indoor and urban magnetic
436  interference makes device-motion panning unreliable, so drag must
437  always work.
438- Third-party feed limits (Launch Library 2) and feed outages: show the
439  last good data with its age.
440- NASA brand rules: the style is borrowed, the branding must not be.
441- A crowded category (SkySafari, Night Sky, Stellarium, Next Spaceflight,
442  SpaceWeatherLive). The case for this app is all of it in one place,
443  designed well, not depth in any one area.
444
445* open questions
446- Pricing: free, paid up front, or free with a one-time unlock for the
447  Library and alerts.
448- Fallback for APNs if Workers' HTTP/2 stops working: Containers sender
449  vs. a separate small VPS. The M0 probe worked, so this is a contingency.
450- Whether the Sky tab needs AR camera overlay at all (current lean: no).