Context. surface studio · domain aja · route /studio/aja/avatar-preview · auth signed-in + studio entitlement · source apps/oshun/web/src/app/studio/aja/avatar-preview/page.tsx
Last walked. 2026-07-02 avatar-lane console addendum — Playwright real-dev-infra coverage now proves signed-in render, route-map contract, quick-action href order, ready form, 44 px submit target, malformed JSON client guard with no POST, real BFF invalid-coverage 400 detail, real LOD active/eligible result rows, fail-closed loading/unauthorized/error states, mobile no-overflow, and direct BFF 401/403/400 gates. Spec: apps/oshun/web/e2e/studio-aja-avatar-lane-consoles.spec.ts.' '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; body re-derived 2026-06-03 from current source (lane-console architecture)
Purpose#
Admin lane console for the real avatar level-of-detail selector. The operator
submits a JSON payload of screenCoverage plus a list of LOD levels (each with
lodId, minScreenCoverage, triangleBudget); the lane picks the
most-detailed LOD whose screen-coverage threshold is met and reads back the
active LOD, its triangle budget, and per-level eligibility — the runtime LOD
decision behind avatar preview rendering.
Entry points#
- Direct URL / bookmark —
/studio/aja/avatar-preview; metadata canonical to this path - Studio nav — Domain-bridge studios section of
/studio - Sibling quick-actions on this page: Avatar Library, Back to Studio (no breadcrumb panel on this route)
- Operator surfacing — see
../../studio-overview.md
Layout regions#
page.tsx renders inside <ShellLayout active="studio">:
- Workspace (
<StudioAjaAvatarPreviewWorkspace />, archetype: LEAF):<h1>(WorkspaceHeading) "Aja Avatar Preview Workspace"- Summary
<p data-aja-avatar-preview-summary>— dense expert-mode controls, progressive disclosure, canonical route map - Live LOD Selector lane (
data-lod-lane,<h2 data-lod-heading>"Live LOD Selector") — the LOD form (see States)
- Route Map panel (
data-aja-avatar-preview-route-map):<h2>Route Map</h2>listing 5 entries fromSTUDIO_AJA_AVATAR_PREVIEW_ROUTE_MAP(primary, scenes, exports, revisions, governance) - Quick-action panel: two
Link.quickActionanchors — Avatar Library, Back to Studio workspace index
States#
- Loading — the LOD lane GETs the catalog on mount; until it resolves
renders
<p data-lod-loading>"Loading LOD selector…" - Unauthorized — 401/403 renders
data-lod-unauthorizedwith the admin-scope message (default "Aja workspace scope required to select a LOD.") - Error — non-OK / unreachable renders
data-lod-error - Ready (form) — success renders the
data-lod-form(adata-lod-payloadtextarea + submit) - Result — a successful POST renders
data-lod-result:data-lod-headline(active LODdata-lod-active+ triangle budget + eligible/level counts) and adata-lod-levelstable ofdata-lod-level-rowrows (each carryingdata-lod,data-active,data-eligible,data-lod-state) - Select error — invalid JSON payload or POST failure renders
data-lod-select-error - Empty / Standalone PWA / offline — no separate empty state exists; the shell SSRs and the lane is a client fetch on mount, with fetch failures collapsing into the verified error state.
Interactions#
Live LOD Selector lane (data-lod-form)#
- LOD levels JSON (
data-lod-payload, textarea, aria-label "lod levels json") — defaults to ascreenCoverage+ 3-level payload - "Select LOD" (
data-lod-submit, submit) — firesPOST /v1/admin/aja/avatar-preview/selectwith the parsed payload
Route Map panel#
- Route entries (5 ×
<article>) — non-interactive path+purpose
Quick-action panel#
- "Open Aja Avatar Library workspace" →
/studio/aja/avatar-library - "Back to Studio workspace index" →
/studio
E2E coverage#
apps/oshun/web/e2e/studio-aja-avatar-lane-consoles.spec.tscovers signed-in shell render, route map shape, exact quick-action hrefs, ready form, 44 px submit target, malformed JSON client guard with no POST, real BFF invalid-coverage 400 detail, real LOD active/eligible result rows, loading/unauthorized/error fail-closed states, mobile no-overflow, and direct BFF auth/schema gates.
Data & contracts#
- Reads:
GET /v1/admin/aja/avatar-previewon mount (catalog probe; body discarded, only auth/availability gates the lane) - Writes:
POST /v1/admin/aja/avatar-preview/select— the LOD payload →{ result }(levels[], activeLod, activeTriangleBudget, summary) - Realtime: none
- Caching: client
fetchon mount withcache: 'no-store'andbuildBffAuthHeaders(); SSR shell only - Auth/role check: BFF endpoints admin-scoped + fail-closed (401/403 → unauthorized render); route behind the signed-in + studio proxy gate
Cross-references#
- Parent:
../../studio-overview.md - Shell:
../../../shell/04-auth-session.md - Sibling routes:
- Component sources:
apps/oshun/web/src/components/studio/StudioAjaAvatarPreviewWorkspace.tsxapps/oshun/web/src/components/studio/StudioAjaAvatarPreviewRouteMap.ts
Known downstream boundaries#
- The LOD lane uses compact
data-lod-*testids while the outer workspace keepsdata-aja-avatar-preview-*anchors. - Route-map sub-routes are advertised contracts; V1 does not ship
page.tsximplementations for those child pages.