Lilith Metaverse · Features

Accessibility, Localization & Quality

A focused page within the Lilith Metaverse Features documentation. The full map and every sibling page live in the Features hub.

4sections11 minread1diagram1table

On this page
flowchart TB Experience[Room class concert Studio or control surface] --> A11y[Input visual audio cognitive motion and comfort variants] Experience --> Locale[Strings speech captions fonts layout and cultural adaptation] Experience --> Telemetry[Versioned functional quality and accessibility signals] A11y --> Tier[Per-client-tier realization and fallback] Locale --> Tier Tier --> Eval[Per-surface automated and human evaluation gates] Telemetry --> Eval Eval --> Release[Named tier locale platform and cohort release] Release --> Observe[Regression support and rollback evidence]

Accessibility, localization, and quality are release inputs for every supported surface/tier. Equivalent member jobs require explicit modality fallbacks and current evidence rather than a single global conformance claim.

Three commitments decide whether the Lilith metaverse is something everyone can actually use, in their own language, with proof that it works: an avatar in a 3D room has to be legible to a screen-reader user and a photosensitive user and a one-thumbed mobile user; a class spoken in English has to read and sound right to an attendee in Seoul or Riyadh standing in the same room; and every one of those claims has to be measured against a hard threshold before it ships. V3 treats all three as engineering surfaces with code behind them, not aspirations in a deck. The accessibility modes and the localization pipeline live as decision engines inside the largest library in V3 — @oshun/tenant-lilith-commons (libs/v3/lilith-commons, a 13,458-line src/index.ts with a 4,536-line, 143-case test suite). The telemetry schema, the eight per-surface eval gates, and the WCAG conformance gate live one layer out in @oshun/analytics, deliberately adjacent to V1's evaluation pipeline so release criteria stay versioned with the rest of Oshun. The shared string catalog and locale formatting are V1's @oshun/i18n, reused rather than forked. This page covers what is real in each, what is honestly a seam, and the gate machinery that refuses to lie about either. The section hub is ../V3_features.md.

What ships, honestly#

The line between real and referenced is consistent across all three areas:

  • Real and tested — the gates and validators. Every accessibility mode and every localization surface is a create*Plan() / build*Report() pair: a deterministic engine that takes a plan, checks it against named domain thresholds (flash rate ≤ 3 Hz, contrast ≥ 4.5, caption p95 ≤ 1 000 ms), and returns a schema-stamped report carrying a passed boolean, a qaReviewStatus of passed / blocked, and an enumerated failures[] list. These are fail-loud decision engines, not config tables — buildV3…Report returns blocked and names the breach the instant a budget regresses. The 143-case suite asserts both the pass path and the block path for each mode.
  • Real evidence, fail-closed gates. The eval-set manifest, the telemetry schema, the eight Grafana boards, and the WCAG QA manifest are real typed artifacts in @oshun/analytics with committed observed runs and validation evidence; the gate functions reject publication on any missing surface, absent threshold, or breached metric.
  • Referenced by string — the in-world rendering. The caption widget floating above an avatar's head, the deuteranopia palette swap on an asana cue, the RTL-mirrored UMG HUD — the actual Unreal rendering is content addressed by path. lilith-commons owns the data, the policy, and the gate; the UE V3Telemetry module is an honest seam that reports its owned surface and instruments nothing (see ../architecture/observability-performance-security-and-launch.md).

Accessibility in 3D#

The seven machine-gated modes#

lilith-commons declares ten accessibility/localization capabilities in its package descriptor, each carrying an operationalMetric string that is the gate in shorthand. Seven are accessibility modes, each with a builder and a report schema:

  • Live avatar captions (buildV3LiveAvatarCaptionReport, schema v3.accessibility.live-avatar-captions.v1). Speech-to-text captions are required on all three surfaces — web, mobile, vr — anchored above the speaker's avatar. The report computes per-surface p95 latency from renderedAtMsBySurface − spokenAtMs, enforces the V3_LIVE_AVATAR_CAPTION_LATENCY_BUDGET_MS = 1_000 ms budget, and verifies the anchor genuinely floats above the head (worldPositionMeters.y > 1.2, followsAvatarTransform, screen position in the top 40%). The test asserts a block with the exact string caption surface mobile p95 latency 1240ms exceeds 1000ms when a surface regresses.
  • Reduced motion (createV3ReducedMotionPlan / buildV3ReducedMotionReport). Caps camera yaw at V3_REDUCED_MOTION_CAMERA_YAW_CAP_DEGREES = 6°, avatar motion at …AVATAR_MOTION_CAP_CENTIMETERS = 1 cm, forces teleport locomotion, disables continuous parallax, and requires snap-turn-only. The "off" path deliberately emits an uncapped plan (yaw 12°, smooth-slide, parallax on) so the gate can prove it blocks the unsafe configuration.
  • Color-vision palettes (buildV3ColorVisionPaletteReport). Three palettes — deuteranopia, protanopia, tritanopia — gated to V3_COLOR_VISION_REQUIRED_PALETTE_COUNT = 3, with asana-cue, marker, and label contrast each held to V3_COLOR_VISION_ASANA_CUE_MIN_CONTRAST_RATIO = 4.5 (the WCAG 2.2 AA contrast floor), plus a ≥ 44 px hit area and ≥ 4 px cue line width per surface. A cue never depends on a single hue.
  • Photosensitive safe mode (buildV3PhotosensitiveSafeModeReport). Holds observed flash rate to V3_PHOTOSENSITIVE_SAFE_MAX_FLASH_RATE_HZ = 3 (the WCAG 2.2 SC 2.3.1 three-flash threshold), caps luminance delta, requires strobe attenuation ≥ 90%, bounds bloom intensity and emissive-pulse amplitude, locks auto-exposure, and disables rapid-cut transitions — the same constraint the concert Sequencer enforces on stage lighting.
  • One-handed mobile HUD (buildV3OneHandedMobileHudReport). Docks nine primary targets into the bottom thumb zone, requiring each to start at ≥ 56% viewport height with a ≥ 44 px hit area; the inventory includes the spatial-audio-off, audio-descriptions, photosensitive-safe, and caption-surface toggles, so the other accessibility modes remain reachable one-handed.
  • Cognitive-load reduction (buildV3CognitiveLoadReductionReport). Caps visible primary controls at 5, holds dwell time ≥ 1 200 ms and transition dwell ≥ 1 000 ms, limits instruction copy to ≤ 7 words, and requires icon+label pairs, progressive disclosure, and disabled autoplay prompts.
  • Keyboard / single-switch navigation (buildV3KeyboardSingleSwitchNavigationReport). Full desktop operability with no pointer, scan cycle ≤ 1 200 ms — the gate that makes the 2D surfaces usable by switch-access users.

Each builder produces a report whose failures[] is computed from real per-surface predicates, not a hardcoded verdict; flipping any input below its floor changes the verdict and the enumerated reason. This is why the suite can assert both report.passed === true on the canonical plan and a specific failure string on a deliberately broken one.

Audio descriptions, spatial-audio-off, and VR comfort — where the line is#

The features brief lists more affordances than lilith-commons gates directly, and the docs are explicit about which is which. Audio descriptions and spatial-audio-off appear in the HUD reach inventory and the keyboard-nav target set (audio-description-toggle, mobile-hud:spatial-audio-off) — so they are gated for reachability — but the audio behavior itself lives in libs/v3/spatial-audio, whose renderer is an hrtf-convolution path with an ambisonic-stereo-fallback (the flat-stereo mix for users with HRTF-induced disorientation). Spatial-audio-off additionally carries its own verifier (verify:v3 spatial-audio-off-mode) in the QA manifest. VR comfort and calibration — vignetting, snap-degree presets, IPD, floor recalibration — are specified in the features and architecture docs and gated through the WCAG QA manifest rather than a lilith-commons builder. Calling this out is the honest posture: the seven modes above have deterministic report engines; the rest are real but live in other libraries or as QA-manifest checklist items.

The WCAG 2.2 AA bar#

The target is WCAG 2.2 AA for 2D surfaces, with the W3C XR accessibility user-needs draft as a north star for the evolving XR work. Crucially, accessibility parity is a tiered-stack requirement: the Tier-2 web fallback must clear the same AA bar as the canonical UE client, and the fallback's WCAG conformance is itself a launch-readiness gate — gated, not aspirational.

Localization#

Eighteen launch locales, real HUD strings, real RTL#

V3 enumerates 18 GA launch locales with a hard floor of 16 (V3_LAUNCH_LOCALIZATION_MIN_LOCALE_COUNT = 16, V3_LAUNCH_LOCALIZATION_REQUIRED_LOCALE_IDS): the three English variants (en-US/GB/IN), es-ES/MX, pt-BR, fr-FR/CA, de-DE, it-IT, hi-IN, ja-JP, ko-KR, zh-CN/TW, ar, he, and yo-NG. Yoruba is in the GA set ahead of the African-region wave-2 launch it supports. Each locale carries a createV3LaunchLocalizationLocalePack with its direction; ar and he are rtl.

The six required HUD strings (hud.enter, hud.stream-status, hud.caption-anchor, hud.accessibility-controls, hud.tara-instructor-voice, hud.saraswati-persona-voice) are translated for all 18 locales in launch-locale-hud-translations.ts, typed satisfies Record<V3LaunchLocaleId, Record<V3LaunchLocalizationHudStringId, string>> so the build fails if any locale is missing a string. The translations are genuinely non-English — Yoruba renders "Enter Lilith" as Wọ Lilith and "Captions" as Ọ̀rọ̀ ìsàlẹ̀, Hebrew as כתוביות — and buildV3LaunchLocalizationLocaleReport computes a differsFromEnglish predicate that blocks a locale whose strings were merely copied through from en-US (English regional variants legitimately share base wording). buildV3LaunchLocalizationReport then ANDs, across every enumerated locale, that HUD strings are localized, the UE-UMG and Tier-2-HTML HUD bundles are QA-validated, subtitle anchors validate on web/mobile/vr, voice dubs are approved, and — for ar/he specifically — the RTL layout validates. A single unvalidated bundle returns qaReviewStatus: 'blocked' with a named failure.

Voice dubbing and cultural adaptation#

Two further localization engines round out the pipeline. The voice-dubbing pipeline (buildV3VoiceDubbingPipelineReport) requires GA jobs for both source kinds — tara-instructor-class and saraswati-artist-speech — each targeting a second locale, clearing a GA quality floor of V3_VOICE_DUBBING_PIPELINE_MIN_GA_QUALITY_SCORE = 0.95, and passing translation, pronunciation, timing, and subtitle review plus a rights gate (voice consent, signature, scope lock, signoff, royalty route) and an adversarial policy gate with zero breaches. The cultural-adaptation review (buildV3CulturalAdaptationReviewReport) gates tradition-sensitive Tara and Commons content through a documented process (anchored to a real V3/CULTURAL_ADAPTATION_REVIEW.md reference and an ISO-timestamped signoff), covering all launch locales with five required review roles, an adaptation brief, a protected-terms glossary, documented prohibited claims, and an approved release signoff applied to GA inventory — so a localized dub cannot flatten lineage-specific material. These engines are what the festival programming and venue content lean on; see ./commons-venues-and-live-service.md.

The shared @oshun/i18n spine#

Underneath the V3 in-world layer sits V1's @oshun/i18n (libs/oshun/i18n, 721 lines) — the canonical catalog for shared customer-facing shell strings. It is a distinct, narrower layer: 8 V1 launch locales (en-US, es-US, fr-FR, de-DE, ar, he, ja-JP, pt-BR) covering 26 cross-shell message keys (assistant.disclosure.ai, evidence.provenance.open, privacy.dsar_received, …), each fully translated, not the 18-locale in-world HUD set. What makes it load-bearing for V3 is the machinery the in-world layer reuses: a documented translate() fallback chain (requested → language-only → en-US) that records a fallbackApplied flag and emits a TranslationFallbackEvent so a missing string logs a gap rather than rendering empty; findFallbackGaps(), which enumerates every <key, locale> pair still resolving via fallback so a pre-launch audit can prove zero gaps; an RTL_LOCALES set and localeDirection helper; per-locale text-expansion budgets (de-DE 1.4×, ja-JP 0.7× relative to en-US) that layout QA verifies; and real Intl.*-based date, currency, number, and relative-time formatting per locale. The V3 promise that "a missing string falls back to US English with a logged gap" is this code, exactly.

Telemetry, eval, and quality#

The versioned telemetry schema#

V3 telemetry rides V1's analytics package and Grafana stack — it adds schemas and boards, not infrastructure. v3-telemetry-schema.ts (published as schema-v3) defines versioned events with an eventId, surface, consent mode, and non-PII property definitions: oshun.accessibility.mode_changed (e.g. mode: keyboard_single_switch, state: enabled), oshun.localization.locale_selected (rtl_layout, voice_dub_available, subtitle_anchor_available), oshun.tier_router.decision_recorded, oshun.safety.report_submitted, and saraswati.music_sync.drift_measured. Trace IDs are intended to span a full session lifecycle, emitted over OpenTelemetry; the world server is the proof point, with its OTLP exporter opt-in behind V3_WORLD_SERVER_OTEL while Prometheus scraping needs no flag. The eight tier-stack dashboards (v3-grafana-dashboards.ts) each carry a named PagerDuty rotation and an alert that fires when its gate is not green.

Eight eval-set release gates, fail-closed#

The heart of "quality" is v3-eval-sets-release-gates.ts: eight required eval surfaces, each with a hard threshold and a direction of min or max.

Surface Metric Gate Observed
World-server tick snapshot_p99_ms ≤ 25 ms 18.4 ms
Gateway latency browser_pop_rtt_p99_ms ≤ 60 ms 44 ms
Voice latency mouth_to_ear_rtt_p95_ms ≤ 80 ms 58 ms
Music-sync drift cross_attendee_drift_p95_ms ≤ 25 ms 19 ms
Aja accuracy canonical_asana_min_per_asana_accuracy ≥ 0.92 0.94
Persona-policy adversarial_policy_breach_count ≤ 0 0
Crisis routing crisis_routing_recall ≥ 1.0 1.0
Harassment SLA harassment_report_action_p95_minutes ≤ 45 min 31 min

buildV3PerSurfaceEvalSetReport and evaluateV3ReleaseGateEvalRun implement the threshold logic directly (direction === 'min' ? value >= threshold : value <= threshold) and fail closed: publication is rejected if a required surface is missing, a threshold is absent, an evidence path is missing, the CI state is not green, or any observed metric misses its bar — a needs_data state for any missing metric, red for any breach. The committed runs all pass, but the manifest is wired so a regressed Aja accuracy or a single persona-policy breach cannot be papered over at release. The eval gate is one constituent of the launch gate, not a standalone green.

The WCAG gate and the honestly-red launch gate#

Accessibility folds into one machine-checked artifact too: v3-testing-qa-accessibility.ts is a fail-closed QA gate whose checklist includes 70.vitest-ts-coverage, 70.axe-web-2d, 70.motion-photosensitive-audio (wiring verify:v3 reduced-motion-mode, verify:v3 photosensitive-safe-mode, verify:v3 spatial-audio-off-mode), keyboard navigation, and a screen-reader audit, emitting V3/qa/testing-qa-accessibility-release-gate.json (status green): Vitest at 84.6% meaningful-line coverage, Playwright on chromium+webkit with zero serious/critical axe violations, and the WCAG 2.2 AA modes at 100% coverage with a signed-off artifact.

All of this feeds the §75 launch-readiness gate, which is the output of scripts/v3/verify-v3-launch-readiness.mjs executing every constituent verifier and ANDing the results. Today it reads status: red, passingGateCount: 30 of 41, gaReady: false — the correct, load-bearing state for a pre-GA build, with the eval and accessibility gates green and the still-open gates (Pixel Streaming fleet 5×, cross-platform certification, GA-inventory rollups) honestly red. That red is the point: the gate is wired so its green is unforgeable. The full launch-and-rollout machinery is covered in ./operations-rollout-and-launch.md, and the observability, eval, and gate architecture in ../architecture/observability-performance-security-and-launch.md.