Game share-loop: instrument funnel, deep-link shares, /play metadata
Sharpen the existing daily-game share loop into something measurable (per Codex's
"instrument what you have, then feed people into it" plan), ahead of a Show HN launch.
Analytics:
- Per-game funnel events <game>_{arrival,started,completed,shared} (article_id=0).
arrival = landed via a shared link (utm_source=game_share); started = first move
(guess/find/flip); completed = solved/cleared/Full Bloom; shared = on share success.
- trackVisit() moved into the global layout so direct /play landings count; the
server-rendered /a/ share page now creates a visitor token + sends a daily visit
beacon (first-time /a/-only visitors were previously dropped).
- Admin "Games funnel" panel: arrivals / engaged / completed / shared, per game.
Sharing:
- Memory Match gains a Share button (it was the only game without one).
- All shares deep-link to the exact game+variant with a full https:// URL +
utm_source=game_share (gameShareUrl helper), instead of a bare /play.
- "shared" is counted only after navigator.share()/clipboard.writeText() succeeds.
/play social metadata:
- /play served homepage canonical/OG (static SPA, ssr=false). postbuild script
patches build/play.html's head to /play canonical/title/description/OG; fails the
build if the homepage tags drift. Caddy try_files now serves {path}.html so /play
is served from the patched file (snapshot in deploy/caddy/).
Tests: backend 352, frontend 27.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
import { auth, refresh as refreshAuth, isFollowing, toggleFollow, followKeys } from '$lib/auth.svelte.js';
|
||||
import { prefs, initPrefs, active as prefsActive, applyPrefAction, persistPrefs, syncPrefsOnLogin } from '$lib/prefs.svelte.js';
|
||||
import { initHistory, deviceIds, record, loadServerHistory } from '$lib/history.svelte.js';
|
||||
import { trackVisit, track } from '$lib/analytics.js';
|
||||
import { track } from '$lib/analytics.js';
|
||||
import { pwa, installApp, dismissPwa } from '$lib/pwa.svelte.js';
|
||||
import { ritualState, markBriefSeen } from '$lib/ritual.js';
|
||||
|
||||
@@ -488,7 +488,7 @@
|
||||
seenIds = new Set(P.loadJSON(SEEN_KEY, []));
|
||||
dismissed = new Set(P.loadJSON(DISMISSED_KEY, []));
|
||||
refreshAuth();
|
||||
trackVisit();
|
||||
// trackVisit() now fires once in the global layout (covers every landing page).
|
||||
if (selected === 'search') { searchText = searchQuery; searchOpen = true; } // prefill on direct/shared link
|
||||
// Instant paint: render the last saved Today brief immediately and refresh
|
||||
// it behind the scenes, so the first view never blocks on a (personalized,
|
||||
|
||||
Reference in New Issue
Block a user