fix(intro): audible entrance oomph, splash off deep routes, finale on intro shortcuts — with e2e cinematic suite
Three first-visit-experience bugs, all caught by the new e2e suite (e2e/intro-experience.spec.ts — 5 tests against the demo stack on real Chrome, instrumenting HTMLMediaElement/WebAudio/MutationObserver since headless can't hear or see the cinematic): - playDashboardLoadOomph was always silent: the login→dashboard route change closes the AudioContext (stopAllAudio), and the oomph only fetched the dead context. It now recreates one, riding the login click's sticky user activation. - A direct /login load in the demo hijacked into the splash: App.vue read route.path before the router resolved the initial navigation, so every deep-route boot looked like a root boot. The splash decision now reads window.location.pathname. - Replayed intros ran mute (enableCinematicSounds override) and the intro's shortcut exits skipped the dashboard finale (flag now armed on both demo and login exits). Verified: 5/5 e2e, 673/673 unit, vue-tsc clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,14 +8,27 @@
|
||||
* exempt and continue to play regardless.
|
||||
*/
|
||||
|
||||
/** One-way, per-page-load override: when App.vue decides to run the intro
|
||||
* splash (demo fresh boot, prod first install, Replay Intro), the WHOLE
|
||||
* cinematic — speech, synthwave, pops — must be audible even though
|
||||
* localStorage already says onboarding is complete. Without this the
|
||||
* replayed intro runs silent (lost "Welcome Noderunner" + song). */
|
||||
let cinematicMode = false
|
||||
export function enableCinematicSounds() {
|
||||
cinematicMode = true
|
||||
}
|
||||
|
||||
/** True when the node has not yet completed onboarding — i.e. we're
|
||||
* still in the first-install cinematic. Reads the localStorage cache
|
||||
* set by useOnboarding (which is re-seeded from the backend on each
|
||||
* successful check), so this stays correct after a browser clear
|
||||
* once the onboarding-complete probe runs. Sound calls that fire
|
||||
* before that probe completes will fall through silent on an already-
|
||||
* onboarded node — which is exactly what we want. */
|
||||
* still in the first-install cinematic — or when the intro is being
|
||||
* deliberately replayed this page load (see enableCinematicSounds).
|
||||
* Reads the localStorage cache set by useOnboarding (which is
|
||||
* re-seeded from the backend on each successful check), so this stays
|
||||
* correct after a browser clear once the onboarding-complete probe
|
||||
* runs. Sound calls that fire before that probe completes will fall
|
||||
* through silent on an already-onboarded node — which is exactly what
|
||||
* we want: ordinary re-logins stay quiet. */
|
||||
function isFirstInstallPhase(): boolean {
|
||||
if (cinematicMode) return true
|
||||
try {
|
||||
return localStorage.getItem('neode_onboarding_complete') !== '1'
|
||||
} catch {
|
||||
@@ -260,7 +273,10 @@ export function playKeyboardTypingSound() {
|
||||
*/
|
||||
export function playDashboardLoadOomph(force = false) {
|
||||
if (!force && !isFirstInstallPhase()) return
|
||||
const ctx = getContext()
|
||||
// The login→dashboard route change runs stopAllAudio(), which CLOSES the
|
||||
// AudioContext — so the context must be recreated here, not just fetched.
|
||||
// The login click's sticky user activation lets the fresh context run.
|
||||
const ctx = ensureContext()
|
||||
if (!ctx) return
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user