Skip to content

fix(visibility): start the initial stack screen visible - #161

Open
ptrnk0 wants to merge 1 commit into
eds2002:mainfrom
ptrnk0:fix/initial-scene-visibility
Open

ptrnk0 wants to merge 1 commit into
eds2002:mainfrom
ptrnk0:fix/initial-scene-visibility

Conversation

@ptrnk0

@ptrnk0 ptrnk0 commented Oct 19, 2026 •

Copy link
Copy Markdown

Motivation

useMaybeBlockVisibility starts every non-overlay screen blocked (useSharedValue(!isFloatingOverlay)), so its animated style first parks the screen off-screen (translateY = getVisibilityBlockOffset(height) = height * 2 + 1) and the gate reaction later flips it to visible on the UI thread.

The first route of a stack never runs an open transition — useOpenTransitionIntent skips it when isFirstKey && !experimental_animateOnInitialMount. For that screen, progress stays at 0 and the gate never "opens"; the screen is visible only because the reaction computes shouldBlock: false and the style mapper applies translateY: 0. That one UI-thread update is the only thing that ever makes it visible.

In a production app (Expo SDK 57, RN 0.86, Reanimated 4.5, expo-router integration) that update was sometimes lost: after a second logout → signup → onboarding in the same JS session, the root BlankStack scene stayed parked at translateY = 2H + 1 and the app showed a blank screen, even though:

  • navigation state and route keys were identical to a working run;
  • the scene's gate state reported shouldBlock: false.

Re-running the style mapper from the debugger (toggling the scene's entering 1 → 0) made the screen appear instantly, which confirms the computed state was correct and only the applied style was stale.

The same initial value is still present in 4.1.0-rc.0 (providers/motion/hooks/use-maybe-block-visibility.tsx).

Change

  • New pure helper resolveInitialVisibilityBlocked({ isFloatingOverlay, isFirstKey, animateOnInitialMount }) next to resolveScreenVisibilityGate. It returns false for floating overlays (unchanged) and for a first-key screen that does not animate on initial mount; true otherwise.
  • useMaybeBlockVisibility seeds localVisibilityBlocked / effectiveVisibilityBlocked with it, using isFirstKey and options.experimental_animateOnInitialMount from the descriptors store, the same condition useOpenTransitionIntent uses.

Pushed screens keep starting blocked (their open is requested in a layout effect after the first render, so an unblocked start would flash them). The initial-destination style gate is unaffected: it only applies to screens with a destinationPairKey, which a first-key screen does not have.

Test plan

  • New resolveInitialVisibilityBlocked cases in visibility-gate.test.ts: first screen starts visible, first screen with animateOnInitialMount starts blocked, pushed screens start blocked, floating overlays never block.
  • bun test: 480 pass, 0 fail
  • bun run lint: clean
  • bun run typecheck: clean
  • Verified in the production app via patch-package on 4.0.0: the blank-screen repro (two signup → onboarding cycles in one session) now lands on Home both times, and a pushed BlankStack screen (settings, zoom preset) still opens with its transition. Not run: the Maestro e2e suite.

Related: #159 (same app, separate BlankStack fix).

🤖 Generated with Claude Code

The visibility gate starts every non-overlay screen blocked, so its
animated style first parks the screen off-screen (translateY = height * 2 + 1)
and a reaction later flips it to visible on the UI thread. The first route
of a stack never runs an open transition (use-open-transition-intent skips
it unless experimental_animateOnInitialMount is set), so that single style
update is the only thing that ever makes it visible. When it is lost, the
screen stays off-screen while the gate state says "visible".

Start such a screen unblocked. Pushed screens keep starting blocked, since
their open is requested in a layout effect after the first render.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@netlify

netlify Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for rnst-docs ready!

Name Link
🔨 Latest commit 245b66a
🔍 Latest deploy log https://app.netlify.com/projects/rnst-docs/deploys/6ad62b184426055fe1d4c066
😎 Deploy Preview https://deploy-preview-161--rnst-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

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