V1 Web PWA · Surface walkthrough

Studio · Generation · Nyx 3D Briefing

A per-surface walkthrough of the V1 Web PWA studio surface: layout, states, interactions, data, and cross-references.

walked
8sections3 minread

On this page

Context. surface studio · domain generation · route /studio/generation/nyx-3d · auth signed-in + creator (proxy-gated; not anonymous, not search-indexed) · source apps/oshun/web/src/app/studio/generation/nyx-3d/page.tsx

Last walked. 2026-06-03 automated runtime probe (Playwright headless) — prod build + mock BFF; render, HTTP 200, server-rendered <h1>, 0 page errors verified. Evidence: WALKTHROUGH/results/walkthrough-runtime-probe-2026-06-03.md

Purpose#

The approved Nyx 3D sky-event briefing surface (§24.6 / §24.8). Renders the Nyx3DBriefingCard against upcoming, ephemeris-derived sky events (GET /v1/isis/nyx-3d/events) and submits through POST /v1/isis/nyx-3d/generate. The 3D pipeline class is server-authoritative — the client only sends the chosen eventId; the backend runs the real sky-event validation + entitlement, then enqueues (Meshy is the registered provider when OSHUN_MESHY_API_KEY is set), fail-closed 503 otherwise.

Entry points#

  • Direct URL / bookmark/studio/generation/nyx-3d (proxy-gated to authed creators; robots: noindex/nofollow/noarchive/nosnippet)
  • Studio shell navactive="studio" (shortcut 6), generation sub-area
  • Sibling generation surfaces — curated-cards / music / living-scene
  • Nyx domain bridge — conceptually downstream of the customer Nyx sky surfaces (/nyx/tonight, /nyx/sky-almanac); the events here are the same ephemeris events surfaced for briefing

Layout regions#

  • Header: shell header (ShellLayout active="studio")
  • Main: <section data-nyx-3d-studio>
    • <h1>Nyx 3D Briefing</h1> — page heading, rendered in all four states (error → inside data-nyx-3d-error; loading → inside data-nyx-3d-loading; empty → inside data-nyx-3d-empty; populated → top of the studio section), plus a lede <p> "Generate a 3D briefing for an upcoming sky event. The pipeline class is server-authoritative; outputs are provenance-tracked."
    • Consent panel (.panel, data-nyx-3d-consent) — single terms checkbox
    • Nyx3DBriefingCard (via CardShell) — sky-event picker + pipeline-class readout + preflight meta + Generate
    • Status line (.panel, data-nyx-3d-status) after a submit attempt

States#

  • Loadingdata-nyx-3d-loading panel "Loading upcoming sky events…" while the GET is in flight, or when the response lacks card / provenance
  • Emptydata-nyx-3d-empty panel "No upcoming sky events are available for a 3D briefing right now." when events.length === 0 (honest empty — no fabricated events)
  • Populated — consent panel + Nyx3DBriefingCard with the event select defaulted to the first upcoming event
  • Entitlement-denied / feature-unavailable — handled by CardShell
  • Submit accepted — "Accepted — queued for 3D briefing generation."
  • Submit rejected (503) — "The 3D sky-briefing provider is not configured for this deployment yet."
  • Submit rejected (403) — "Not available: "
  • Submit rejected (404) — "That sky event is no longer upcoming."
  • Submit rejected (422) — "This briefing is outside the approved envelope."
  • Error (load failed)data-nyx-3d-error "The Nyx 3D briefing surface is unavailable right now: "
  • Offline — load GET fails → error panel; submit POST → "Submission failed."
  • Gated — proxy (creator) + entitlement (server)
  • Standalone PWA — renders within shell

Interactions#

  • Terms consent (checkbox, data-nyx-3d-consent-checkbox)
    • Function: toggles consentAccepted; sets consentId to consent-nyx3d-<userId> when accepted
    • Screen reader: announces "I accept the curated-generation terms for this 3D sky briefing."
  • Sky event (select, data-field="eventId")
    • Function: chooses the SkyEventBriefing; options are availableEvents[].eventLabel; selecting one shows its approved pipeline class (<code>{approvedPipelineClassId}</code>)
    • inputsValid is true only when a listed event is selected
  • Direction (textarea) — regenerate steer
  • Generate (button, data-card-action="generate")
    • Function: submit({ eventId, pipelineClassId }); only eventId is sent on the wire (POST /v1/isis/nyx-3d/generate body { eventId }) — the pipeline class is resolved server-side
    • Disabled when: no event selected / preflight blocked / no consent / busy
  • Regenerate with direction, Variant compare, Send to editorial, Takedown — shared CardShell controls (last two () => undefined)

Data & contracts#

  • Reads: GET /v1/isis/nyx-3d/events{ events: SkyEventBriefing[], creatorTier, card: CardSpec | null, provenance: ProvenancePreview | null } where SkyEventBriefing = { eventId, eventLabel, approvedPipelineClassId }
  • Writes: POST /v1/isis/nyx-3d/generate{ eventId } only; pipeline-class server-authoritative; fail-closed 503 until provider configured
  • Realtime: None.
  • Caching: client fetch on mount
  • Auth/role check: proxy (creator) + entitlement (server) + sky-event validity (server, "no longer upcoming" → 404)
  • Contracts: @oshun-web/isis-curated-cards (CardSpec, ConsentConfirmation, ProvenancePreview, PENDING_COST_COEFFICIENTS); SkyEventBriefing defined inline + in Nyx3DBriefingCard.tsx

Cross-references#

Open questions / known gaps#

  • tenantId is '' and userId defaults to 'me' in Nyx3DStudio — confirm session/proxy resolution.
  • Confirm the eventId set here is sourced from the same ephemeris that feeds /v1/nyx/tonight and /v1/nyx/sky-almanac, so a customer-visible event and its 3D briefing always agree.