Skip to content

No login screen inside MiniPay, not even for a frame - #225

Merged
0xward merged 1 commit into
mainfrom
claude/nullstate-onchain-text-q6g2a3
Aug 2, 2026
Merged

No login screen inside MiniPay, not even for a frame#225
0xward merged 1 commit into
mainfrom
claude/nullstate-onchain-text-q6g2a3

Conversation

@0xward

@0xward 0xward commented Aug 2, 2026

Copy link
Copy Markdown
Owner

The owner found this by opening the game inside MiniPay: the login screen appeared and vanished. He is right that it matters — a screen between the player and the game is what MiniPay's listing rules reject, and "only for a moment" is not a defence.

The rule was never wrong. The timing was.

isMiniPay is read from window.ethereum inside WagmiIsland, and lib/Web3Providers.tsx mounts that island on requestIdleCallback with a 1500 ms ceiling. Until it mounts, the bridge serves its defaults — isMiniPay: false — so shouldOfferSignIn() answered "yes, ask them" to a MiniPay player for up to a second and a half.

The obvious fix was measured and thrown away

Holding the gate until walletReady:

result
inside MiniPay gate never appeared ✅
outside MiniPay map at 50 ms, gate at 1272 ms

A login landing on top of a map the player has already been looking at for a second is the first complaint wearing a different hat. So the wait is gone.

Where the guarantee lives instead

privyGateFlag reads window.ethereum.isMiniPay directly. It needs nothing mounted — MiniPay injects the provider before page scripts run — so it is correct on the very first render, which is exactly the window the gate was flashing in. It runs before the query-string override, because there is no argument for a URL that can force a login screen into MiniPay.

A synchronous read has one failure mode: a provider injected a moment late. So the flag is re-evaluated every 100 ms for 1.5 s — the same ceiling wagmi gets — and it can only ever flip the gate off. Three independent guards now, and every one of them is one-way.

Measured after the change

Polling every 30 ms for 5 seconds, against a build carrying a real app id:

inside MiniPay   0 of 165 polls — never appeared
outside          appears, as it should

Testing

✓ 27/27 test:privy   ✓ tsc clean   ✓ build 142/242 kB (unchanged)
✓ check:copy         ✓ lint 35

The screen itself did not change, so the previously approved screenshot still stands.

One thing this does not fix, reported separately rather than buried here: outside MiniPay the world map is in the prerendered HTML, so it paints before any JavaScript runs and is briefly visible under the gate. That is deliberate — it is what /game's LCP optimisation buys — and removing it would cost MiniPay its fast first paint. Worth a decision, not a silent change.


Generated by Claude Code

OWNER, testing in MiniPay: *"masih sempet muncul halaman loginnya, meskipun
sekedip langsung hilang, tetapi masih muncul, itu betulan mengganggu kedepannya
jika game ku berhasil listing."* Right on both counts. A screen between the
player and the game is what MiniPay's listing rules reject, and "only for a
moment" is not a defence.

The rule was never wrong; the TIMING was. `isMiniPay` is read from
window.ethereum inside WagmiIsland, and lib/Web3Providers.tsx mounts that island
on requestIdleCallback with a 1500ms ceiling. Until it mounts the bridge serves
its defaults — `isMiniPay: false` — so shouldOfferSignIn() answered "yes, ask
them" to a MiniPay player for up to a second and a half.

The obvious fix was to hold the gate until `walletReady`. It was written,
measured, and thrown away:

    inside MiniPay   gate never appeared                          ✓
    outside          map at 50ms, gate at 1272ms                  ✗

A login landing on top of a map the player has been looking at for a second is
the FIRST complaint wearing a different hat. So the wait is gone and the
guarantee moved to where it costs nothing: privyGateFlag reads
window.ethereum.isMiniPay directly, needs nothing mounted, and is therefore
right on the very first render. It runs before the query-string override too —
there is no argument for a URL that can force a login screen into MiniPay.

A synchronous read has exactly one failure mode: a provider injected a moment
late. So the flag is re-evaluated every 100ms for 1.5s, the same ceiling wagmi
gets, and it can only ever flip the gate OFF.

Measured after the change, polling every 30ms for 5 seconds against a build
carrying a real app id:

    inside MiniPay   0 of 165 polls — never appeared
    outside          appears, as it should

Verified: tsc clean, build unchanged at 142/242 kB, 27/27 test:privy,
check:copy clean, lint 35.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017A764RdnwpyWnG7uCNhMiQ
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nullstate Ready Ready Preview Aug 2, 2026 4:52pm

@0xward
0xward merged commit b8e8769 into main Aug 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant