From 4f51077e1450d0ab0d792d3e85d58852a20956af Mon Sep 17 00:00:00 2001 From: Mark Smith Date: Sun, 18 Oct 2026 20:26:57 +0100 Subject: [PATCH 1/3] feat(tutorial): GA4 events for exit and completion-to-play MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fire two GA4 events so the newbie funnel can tell early exits from finishers: - exit_tutorial — when a player clicks Exit Tutorial - tutorial_complete_play — when they click Play MUME Now at the end (screen + modal) Both carry the current chapter. GA is already configured in the theme, so this only sends named events; nothing else changes. Co-Authored-By: Claude Opus 4.8 --- .../theme/components/TutorialPlayer.vue | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/.vitepress/theme/components/TutorialPlayer.vue b/docs/.vitepress/theme/components/TutorialPlayer.vue index a67f901..fb56182 100644 --- a/docs/.vitepress/theme/components/TutorialPlayer.vue +++ b/docs/.vitepress/theme/components/TutorialPlayer.vue @@ -105,6 +105,15 @@ function closeModal() { isModalOpen.value = false } +// Fire a GA4 event when a player leaves the tutorial early (exit_tutorial) or +// finishes and heads to the game (tutorial_complete_play). GA is already set up in +// the theme; this only sends a named signal with the chapter they were on. +function trackTutorial(name: string) { + try { + ;(window as any).gtag?.('event', name, { event_category: 'tutorial', chapter: chapterNum.value }) + } catch { /* analytics is best-effort, never block navigation */ } +} + function openImageModal(src: string, alt = '') { activeModalImage.value = { src, alt } } @@ -699,7 +708,7 @@ onUnmounted(() => { {{ isExpanded ? 'Shrink' : 'Full' }} - + Exit @@ -777,7 +786,7 @@ onUnmounted(() => {

You have mastered movement, equipment, stats, combat, scouting, skills, and resting in Middle-earth.

@@ -879,7 +888,7 @@ onUnmounted(() => {

- + Play MUME Now (Web Client) → From 67b4d50af64765842174ddb0a6a623255cd79bad Mon Sep 17 00:00:00 2001 From: Mark Smith Date: Sun, 18 Oct 2026 20:35:41 +0100 Subject: [PATCH 2/3] fix(tutorial): address review on GA events - Guard exit_tutorial behind a tutorialCompleted flag (set when the end-of-tutorial modal opens), so finishers who later click Exit are not counted as early exits. - Drop the @click on the dead end-screen link (the 'end' beat is never generated, so that branch never renders); completion is tracked on the modal's Play button. - Log caught analytics errors via console.debug instead of swallowing them. Co-Authored-By: Claude Opus 4.8 --- .../theme/components/TutorialPlayer.vue | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/.vitepress/theme/components/TutorialPlayer.vue b/docs/.vitepress/theme/components/TutorialPlayer.vue index fb56182..a365cb6 100644 --- a/docs/.vitepress/theme/components/TutorialPlayer.vue +++ b/docs/.vitepress/theme/components/TutorialPlayer.vue @@ -95,10 +95,14 @@ const entry = ref('') const isSheetOpen = ref(false) const isExpanded = ref(false) const isModalOpen = ref(false) +const tutorialCompleted = ref(false) const activeModalImage = ref<{ src: string; alt: string } | null>(null) function openModal() { isModalOpen.value = true + // Reaching the end-of-tutorial modal means the player finished, so a later Exit + // click should not be counted as an early exit. + tutorialCompleted.value = true } function closeModal() { @@ -111,7 +115,16 @@ function closeModal() { function trackTutorial(name: string) { try { ;(window as any).gtag?.('event', name, { event_category: 'tutorial', chapter: chapterNum.value }) - } catch { /* analytics is best-effort, never block navigation */ } + } catch (err) { + // Analytics is best-effort and must never block navigation; surface it quietly. + console.debug('tutorial analytics event failed', name, err) + } +} + +// The Exit control is always visible, including after completion, so only count a +// click as an early exit when the player has not reached the end-of-tutorial screen. +function trackExit() { + if (!tutorialCompleted.value) trackTutorial('exit_tutorial') } function openImageModal(src: string, alt = '') { @@ -708,7 +721,7 @@ onUnmounted(() => { {{ isExpanded ? 'Shrink' : 'Full' }} - + Exit @@ -786,7 +799,7 @@ onUnmounted(() => {

You have mastered movement, equipment, stats, combat, scouting, skills, and resting in Middle-earth.

From 5b9471195a76ce95b52213cb8f4ec8be0e432aad Mon Sep 17 00:00:00 2001 From: Mark Smith Date: Sun, 18 Oct 2026 20:50:09 +0100 Subject: [PATCH 3/3] fix(tutorial): reset completion flag on chapter change Chapter navigation is SPA (router.go), so the component is not remounted and tutorialCompleted would persist. Reset it in the route watcher so a retake-then-exit is still counted as an exit. Co-Authored-By: Claude Opus 4.8 --- docs/.vitepress/theme/components/TutorialPlayer.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/.vitepress/theme/components/TutorialPlayer.vue b/docs/.vitepress/theme/components/TutorialPlayer.vue index a365cb6..4673fe2 100644 --- a/docs/.vitepress/theme/components/TutorialPlayer.vue +++ b/docs/.vitepress/theme/components/TutorialPlayer.vue @@ -632,6 +632,9 @@ function submit() { } watch(() => route.path, () => { + // Navigation here is SPA, so this component is not remounted between chapters. + // Clear the completion flag on each chapter so a retake-then-exit is counted. + tutorialCompleted.value = false renderStepLog() }, { immediate: true })