---
path: /studio/generation-gallery
surface: studio
domain: generation
auth: signed-in + studio entitlement
source: apps/oshun/web/src/app/studio/generation-gallery/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md'
---

# Studio · Generation Gallery

## Purpose

Unified output gallery (§24.10) for generated illustrations, narrations, ambient
audio, captions, 3D briefings, and accessibility passes. Reads only records the
caller is entitled to via the §24.1 tier resolver, applies filter facets, and
surfaces lineage / branch / replay-with-tweak / compare grid via the
`GenerationGalleryClient` component.

## Entry points

- **Studio root** (`/studio`) — discoverable as a generation workspace
- **Direct URL / bookmark** — yes (signed-in + studio entitlement)
- **Deep link from authoring/compose** — once a generation completes

## Layout regions

`page.tsx` is a server component that calls `loadGalleryViewForRequest()` to
fetch the gallery view, then renders the client component:

```ts
return <GenerationGalleryClient view={view} />;
```

The client component (`GenerationGalleryClient`, ≈ 716 LOC) renders the gallery
shell directly — no `ShellLayout` wrapper.

- **Header**: gallery toolbar
- **Filter facets**: kind (image / video / audio-narration / audio-music /
  mesh-3d / caption-dub / accessibility-pass), domain (tara / veritas / nyx /
  nisaba / metis / arete / sophia), CSV inputs for additional attribute filters
- **Record grid**: output records with kind badge, domain badge, lineage hint
- **Lineage tree**: per-output `OutputLineage` visualization
- **Branch / replay-with-tweak drawer**: composes a `BranchRunRequest` via
  `planBranch`
- **Compare grid**: 2-up / 4-up / n-up layouts via `buildCompareGrid` plus
  per-pair diff metrics (pixel / frame / waveform / mesh-vertex)
- **Provenance inspector**: `GeneratedArtifactProvenanceInspector` renders the
  C2PA-style provenance bundle for a record

## States

- [ ] **Loading** — server-rendered; view object pre-populated
- [ ] **Empty (entitled but no records)** — empty-state copy
- [ ] **Populated** — at least one record per kind / domain
- [ ] **Filter facets applied** — record grid reduces to matching records
- [ ] **Filter excludes all** — empty state with reset CTA
- [ ] **Lineage tree shown** — selecting a record renders its `OutputLineage`
- [ ] **Branch drawer open** — `planBranch` returns the proposed
      `BranchRunRequest`
- [ ] **Compare 2-up / 4-up / n-up** — selecting multiple records sets the
      layout via `chooseCompareLayout(count)`; per-pair diff metrics show under
      each pair
- [ ] **Provenance inspector open** — bundle metadata visible
- [ ] **Error (recoverable)** — `loadGalleryViewForRequest` failure renders
      error state
- [ ] **Offline** — last-loaded gallery view rendered from SW cache where pinned
- [ ] **Standalone PWA** — usable

## Interactions

### Filter facets

- [ ] **Kind toggle chips** (7 chips) — toggle inclusion via `toggleOf`
- [ ] **Domain toggle chips** (7 chips) — toggle inclusion via `toggleOf`
- [ ] **CSV input** (attribute) — `csvToList` parses comma-separated values

### Record grid

- [ ] **Per-record card** — click selects; show kind, domain, lineage hint, cost
- [ ] **"Open lineage"** (button) — renders the `OutputLineage` tree
- [ ] **"Branch / replay with tweak"** (button) — opens the drawer

### Lineage tree

- [ ] **Tree nodes** — per-record provenance edges from `LineageEdge`

### Branch / replay-with-tweak drawer

- [ ] **Parameter range editors** — `ParameterAllowedRange`
- [ ] **"Submit branch run"** (button) — emits the `BranchRunRequest`

### Compare grid

- [ ] **Layout toggle** (2-up / 4-up / n-up) — read-only computed from count
- [ ] **Per-pair diff metric label** — pixel delta / frame delta / audio RMS
      delta / waveform correlation / mesh delta

### Provenance inspector

- [ ] **Bundle metadata view** — rendered by
      `GeneratedArtifactProvenanceInspector`

## Data & contracts

- **Reads**: `loadGalleryViewForRequest()` (server-side) → `GalleryView`
  (filters + records)
- **Library**: `@oshun-web/isis-output-gallery` — `applyGalleryFilter`,
  `buildCompareGrid`, `planBranch`, `OutputLineage`
- **Writes**: branch / replay-with-tweak emits a `BranchRunRequest` to the
  upstream generation surface (separate route)
- **Realtime**: none in this view
- **Caching**: SSR + client SWR for filtered records
- **Auth/role check**: middleware (signed-in + studio entitlement); the loader
  applies the §24.1 tier resolver before returning records

## Cross-references

- Parent: [`../studio-overview.md`](../studio-overview.md)
- Sibling:
  [`studio-generation-living-scene.md`](./studio-generation-living-scene.md),
  [`studio-asset-preview-pipeline.md`](./studio-asset-preview-pipeline.md),
  [`../authoring/studio-compose.md`](../authoring/studio-compose.md)
- Source:
  `apps/oshun/web/src/app/studio/generation-gallery/GenerationGalleryClient.tsx`,
  `apps/oshun/web/src/app/studio/generation-gallery/loader.ts`,
  `apps/oshun/web/src/components/provenance/GeneratedArtifactProvenanceInspector.tsx`

## Open questions / known gaps

- [ ] Confirm whether the gallery view ever streams new records (Psyche
      envelope) or only reloads on filter change
- [ ] Document the C2PA / provenance bundle storage path once moved off seeded
      fixtures
