← World map and portals · all tasks

What playing it actually found — starting at home, closed doors, a keyboard on iPad, and the builds nobody had shipped

done priority 1 estimate L

world-map-and-portals/010 · created 2026-08-16 · updated 2026-08-18

What prompted it

Kris played the deployed build on a phone, an iPad and a laptop on 2026-08-16 and found six things. Every one of them was real.

1. Strangers standing in the world

The live Village contained MapProbe, Wanderer-6137, E2E-Verifier, Sir K and a second MapProbe, clustered on the spawn cell. They were the verification scripts’ own characters — the live verifiers create a guest, join, walk, and their entity persists in the world snapshot. Cleared, and noted as a recurring hazard: any live verify run leaves a character behind until someone empties state->'entities' for the authored areas.

2. A new player started in the commons, among those strangers

The client joined the public world by default. Now there is a join_home_world RPC and new adventurers start in their own home, walking out of the front door into the Village. A better first minute, and the first thing a player sees is a place that is theirs.

3. A door that teleported you to the corner of the map

The Village’s portal at (20,0) leads to the Wizard Battle Pit, which is restricted. Walking into it refused the transfer — and because the transfer erases your entity from the source world before the director answers (that is what makes crash-safety hold), a refusal left the player with no entity at all. The client’s recovery re-said hello and the world built a brand-new entity at the default spawn: the top-left corner, silently, with no message.

Now a refusal restores the actual entity — same id, same character — at the cell the player stepped in from, and the HUD says “That way is closed to you — for now.” The portal.test.ts case that documented this as a known gap has been rewritten to assert the fix.

4. Hidden portals weren’t hidden in the game

hidden_unless_passable filtered the world map but not the world. The in-game grid is hydrated per area, shared by everyone in it, so it can’t answer a per-player question. The director now works out at join time which doors this account may not see and sends the list with the join grant — one shared grid, drawn differently per player. Tested with a stranger and a member standing in the same area seeing different doors.

5. No keyboard on iPad

Godot’s web export draws to a canvas, so there is no focused DOM element for the browser to raise a keyboard for, and DisplayServer.virtual_keyboard_show() is a no-op on web. Every text field in the game was dead on a touch device — signup included, which is a hard stop.

Fixed with a real DOM <input> floated over the canvas (game/shell/text-input.js), hooked into every LineEdit at the factory (theme/lor_forms.gd) via theme/web_keyboard.gd. Touch devices only, so laptop web is untouched. iOS only opens the keyboard for a genuine gesture on a real input, so the focus call is synchronous inside the tap that focused the Godot field — anything deferred and Safari refuses.

Not verified on a real iPad from this session — the plumbing is tested and deployed; the device check is Kris’s.

6. The Android build was never deployed

Correct. The world-map work went out to the web and the server, and the APK was left at the 2026-08-13 build — so the phone showed no map, no profile menu and no portals. Built and uploaded twice today under the line-in-the-sand rule: APK_NAME v1 → v2 → v3, with play.astro’s download link following each time.

Verified

Director 150 tests, Godot 116. On production: a new account lands in its own 16×16 home with one door at the bottom middle and nobody else inside; the public map is unchanged; both builds are live.

View source in repository · also available as raw markdown.