The invitation is four letters, not a link

A URL only opens the installed app on Android; on an iPhone it opened a second
copy of the game in Safari, with its own storage and none of the name picked in
the app. So the share sheet now sends "JOIN ME IN SPLATTER TENNIS — THE CODE IS
ABCD" and nothing else, and the button says SEND THE CODE.

The #net-ABCD door stays — it is exactly what a deep link will carry the day
this is a real app with universal links. Nothing sends it in the meantime.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-15 16:56:25 +02:00
1 parent 89b2488d3c
commit 2b7eb04e19
3 files changed
+21 -19

No files matched your search

+10 -6
View File
@@ -430,12 +430,16 @@ screen (`#vs`, `index.html` + THE LOBBY in `main.js`); the protocol underneath i
the kit/tour selection `start()` performs is already done when the `look` message reads it.
Two more hooks join `intoSplatter`: `room` (the code landed) and `lost` (returns true when the
lobby said so itself, which is what suppresses the card). Headless leaves them null.
- **SHARE THE LINK, then the code.** `navigator.share` is the phone's own sheet — the friend is in
WhatsApp, not in a room reading letters aloud — with `clipboard.writeText` as the desktop
fallback and the four letters still big on screen for when they are in the same room. The link is
the URL door that already existed (`#net-ABCD`): it opens the lobby with the code prefilled,
ONE tap from the court. Deliberately not an auto-join — that tap is where the joiner sees, and
can change, the name the other phone will call them.
- **SEND THE CODE — and no link (settled same day).** `navigator.share` is the phone's own sheet —
the friend is in WhatsApp, not in a room reading letters aloud — with `clipboard.writeText` as
the desktop fallback. It shipped as SHARE THE LINK for an hour and the link came straight back
out: **a URL only opens the INSTALLED app on Android** (the manifest's scope covers the site, so
its WebAPK claims these URLs), while **an iOS home-screen app can claim nothing**, so on an
iPhone the invitation opened a second copy of the game in Safari — its own storage, none of the
name they picked in the app. Four letters typed into the app they already have is the honest
version until this is a real app with universal links; the `#net-ABCD` door still exists and is
exactly what a deep link will carry the day there is one, nothing merely sends it now. That door
prefills the lobby rather than auto-joining, so the joiner still sees the name they will wear.
- **ONE NAME PER PLAYER.** The field is prefilled from `stats.savedName()` and written back through
the new `stats.saveName` (which `submit` now shares), so the world board's name and the netplay
name cannot become two things. It crosses on the EXISTING `look` message as `n` — no new message
+2 -2
View File
@@ -567,7 +567,7 @@ if (location.hostname !== 'splatter-tennis.wuwi.one') {
<div class="mid cent">
<h3 id="vsWHdr" class="cent">ROOM CODE</h3>
<p id="vsBig">····</p>
<button class="btn big" id="vsShare">SHARE THE LINK</button>
<button class="btn big" id="vsShare">SEND THE CODE</button>
<p class="none cent" id="vsMsg">WAITING FOR THEM TO JOIN</p>
</div>
<div class="foot bare"><button class="btn" id="vsCancel">CANCEL</button></div>
@@ -645,6 +645,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one') {
</div>
</div>
</div>
<script type="module" src="src/main.js?v=267"></script>
<script type="module" src="src/main.js?v=268"></script>
</body>
</html>
+9 -11
View File
@@ -163,8 +163,6 @@ buildSub();
const vsPick = document.getElementById('vsPick'), vsWait = document.getElementById('vsWait');
const vsName = document.getElementById('vsName'), vsCode = document.getElementById('vsCode');
const vsSay = (id, text) => { document.getElementById(id).textContent = text; };
// the link IS the invitation: the joiner's phone opens the lobby with the code already in the field
const vsLink = code => location.origin + location.pathname + '#net-' + code;
function vsOpen(code = '') {
vsName.value = stats.savedName();
@@ -193,17 +191,17 @@ vsCode.addEventListener('keydown', e => { if (e.key === 'Enter') vsGo(true); });
// SHARE, then COPY. navigator.share is the phone's own sheet (WhatsApp, Signal, wherever the
// friend actually is) and is exactly the "easier setup" — the clipboard is the desktop fallback,
// and the code stays on screen for the two of them in the same room reading it aloud.
// THE CODE RIDES THE MESSAGE, not just the link. An Android phone opens the link in the INSTALLED
// app (the manifest's scope covers the whole site, so its WebAPK claims these URLs) — but an iPhone
// home-screen app can claim nothing, so the link always opens in Safari, which keeps its own
// storage and therefore knows nothing about the name they picked inside the app. Four letters in
// the same message is the whole fix: a friend who has it installed opens their app and types them.
// THE MESSAGE IS THE CODE, and deliberately carries no link. A link only opens the INSTALLED app
// on Android (the manifest's scope covers the site, so its WebAPK claims these URLs); an iOS
// home-screen app can claim nothing, so on an iPhone it always opened Safari instead — a second
// copy of the game, with its own storage and none of the name they picked in the app. Until this
// is a real app with universal links, four letters are the invitation. (`#net-ABCD` still works as
// a door — it is what a deep link will carry the day there is one — nothing just sends it now.)
document.getElementById('vsShare').addEventListener('click', async () => {
const code = G.net && G.net.code || '';
const url = vsLink(code), text = 'COME AND PLAY ME — ROOM CODE ' + code;
const text = 'JOIN ME IN SPLATTER TENNIS — THE CODE IS ' + (G.net && G.net.code || '');
try {
if (navigator.share) await navigator.share({ title: 'SPLATTER TENNIS', text, url });
else { await navigator.clipboard.writeText(text + ' ' + url); vsSay('vsMsg', 'COPIED — SEND IT TO THEM'); }
if (navigator.share) await navigator.share({ title: 'SPLATTER TENNIS', text });
else { await navigator.clipboard.writeText(text); vsSay('vsMsg', 'COPIED — SEND IT TO THEM'); }
} catch { /* a cancelled share sheet is not an error */ }
});
const vsQuit = () => { endNetVs(); vsOpen(); }; // a room you walked out of must give its socket back