@@ -2459,52 +2459,97 @@ window.addEventListener('orientationchange', () => {
24592459 } , 100 ) ;
24602460} ) ;
24612461
2462- // Update mobile viewport height dynamically - COMPREHENSIVE mobile support
2462+ // Update mobile viewport height dynamically - Enhanced for iOS Safari and Chrome mobile
24632463function updateMobileViewport ( ) {
2464- // Only run on mobile devices
2465- if ( window . innerWidth <= 768 ) {
2466- // Set CSS custom property for consistent viewport height
2467- const vh = window . innerHeight * 0.01 ;
2464+ // Enhanced mobile detection
2465+ const isMobile = window . innerWidth <= 768 ||
2466+ / A n d r o i d | w e b O S | i P h o n e | i P a d | i P o d | B l a c k B e r r y | I E M o b i l e | O p e r a M i n i / i. test ( navigator . userAgent ) ;
2467+
2468+ if ( isMobile ) {
2469+ // Use dynamic viewport units when supported
2470+ let viewportHeight = window . innerHeight ;
2471+
2472+ // iOS Safari specific fixes
2473+ if ( / i P a d | i P h o n e | i P o d / . test ( navigator . userAgent ) && ! window . MSStream ) {
2474+ // Account for iOS Safari's dynamic UI
2475+ viewportHeight = window . visualViewport ? window . visualViewport . height : window . innerHeight ;
2476+ }
2477+
2478+ // Set CSS custom properties for both standard and dynamic viewport
2479+ const vh = viewportHeight * 0.01 ;
2480+ const dvh = viewportHeight * 0.01 ;
24682481 document . documentElement . style . setProperty ( '--vh' , `${ vh } px` ) ;
2482+ document . documentElement . style . setProperty ( '--dvh' , `${ dvh } px` ) ;
24692483
2470- // Force canvas sizing for mobile
2484+ // Enhanced canvas sizing for mobile browsers
24712485 const canvas = document . getElementById ( 'webglCanvas' ) ;
24722486 if ( canvas ) {
2473- canvas . style . width = '100vw' ;
2474- canvas . style . height = '100vh' ;
2475- canvas . style . position = 'fixed' ;
2476- canvas . style . top = '0' ;
2477- canvas . style . left = '0' ;
2487+ canvas . style . cssText = `
2488+ width: 100vw !important;
2489+ height: 100vh !important;
2490+ height: ${ viewportHeight } px !important;
2491+ position: fixed !important;
2492+ top: 0 !important;
2493+ left: 0 !important;
2494+ z-index: 0 !important;
2495+ touch-action: none !important;
2496+ -webkit-user-select: none !important;
2497+ user-select: none !important;
2498+ ` ;
24782499 }
24792500
2480- // Optimize HUD positioning for mobile browsers
2501+ // Optimize HUD positioning for different mobile browsers
24812502 const bottomHud = document . getElementById ( 'bottomHud' ) ;
24822503 const topHud = document . getElementById ( 'topHud' ) ;
24832504
24842505 if ( bottomHud ) {
2485- // Smart bottom HUD positioning
24862506 const isLandscape = window . innerWidth > window . innerHeight ;
2487- const viewportHeight = window . innerHeight ;
2488- const safeAreaBottom = getComputedStyle ( document . documentElement ) . getPropertyValue ( '--sab' ) || '0px' ;
2507+ const safeAreaBottom = getComputedStyle ( document . documentElement )
2508+ . getPropertyValue ( '--sab' ) ||
2509+ getComputedStyle ( document . documentElement )
2510+ . getPropertyValue ( 'env(safe-area-inset-bottom)' ) || '0px' ;
24892511
2490- // Position based on actual viewport and orientation
2512+ // Enhanced bottom HUD positioning for mobile browsers
2513+ let bottomOffset = 12 ;
24912514 if ( isLandscape && viewportHeight < 500 ) {
2492- bottomHud . style . bottom = `max(10px, ${ safeAreaBottom } )` ;
2515+ bottomOffset = 8 ;
24932516 } else if ( viewportHeight < 600 ) {
2494- bottomHud . style . bottom = `max(15px, ${ safeAreaBottom } )` ;
2495- } else {
2496- bottomHud . style . bottom = `max(20px, ${ safeAreaBottom } )` ;
2517+ bottomOffset = 10 ;
24972518 }
24982519
2499- // Ensure buttons are touchable
2500- bottomHud . style . pointerEvents = 'auto' ;
2501- bottomHud . style . zIndex = '999' ;
2520+ bottomHud . style . cssText += `
2521+ bottom: max(${ bottomOffset } px, ${ safeAreaBottom } ) !important;
2522+ pointer-events: none !important;
2523+ z-index: 999 !important;
2524+ position: fixed !important;
2525+ left: 8px !important;
2526+ right: 8px !important;
2527+ width: auto !important;
2528+ background: linear-gradient(135deg, rgba(0, 255, 255, 0.25), rgba(0, 0, 0, 0.9)) !important;
2529+ border: 2px solid #00ffff !important;
2530+ box-shadow: 0 0 25px rgba(0, 255, 255, 0.6) !important;
2531+ ` ;
2532+
2533+ // Make HUD controls touchable
2534+ const hudControls = bottomHud . querySelector ( '.hud-controls' ) ;
2535+ if ( hudControls ) {
2536+ hudControls . style . pointerEvents = 'auto' ;
2537+ hudControls . style . zIndex = '1000' ;
2538+ }
25022539 }
25032540
25042541 if ( topHud ) {
2505- // Minimize top HUD interference
2506- topHud . style . pointerEvents = 'auto' ;
2507- topHud . style . opacity = '0.9' ;
2542+ const safeAreaTop = getComputedStyle ( document . documentElement )
2543+ . getPropertyValue ( '--sat' ) ||
2544+ getComputedStyle ( document . documentElement )
2545+ . getPropertyValue ( 'env(safe-area-inset-top)' ) || '0px' ;
2546+
2547+ topHud . style . cssText += `
2548+ top: max(4px, ${ safeAreaTop } ) !important;
2549+ pointer-events: auto !important;
2550+ opacity: 0.95 !important;
2551+ backdrop-filter: blur(8px) !important;
2552+ ` ;
25082553 }
25092554
25102555 // Force layout recalculation
@@ -2571,8 +2616,110 @@ window.addEventListener('load', () => {
25712616 soundManager . setMasterVolume ( gameSettings . volume ) ;
25722617 } ) ;
25732618
2574- // Initialize mobile viewport handling
2619+ // Enhanced mobile initialization
2620+ initializeMobileSupport ( ) ;
2621+ } ) ;
2622+
2623+ // Enhanced mobile support initialization
2624+ function initializeMobileSupport ( ) {
2625+ console . log ( '📱 Initializing enhanced mobile support...' ) ;
2626+
2627+ // Initial mobile viewport setup
25752628 updateMobileViewport ( ) ;
2629+
2630+ // Enhanced mobile event listeners
2631+ const isMobile = window . innerWidth <= 768 ||
2632+ / A n d r o i d | w e b O S | i P h o n e | i P a d | i P o d | B l a c k B e r r y | I E M o b i l e | O p e r a M i n i / i. test ( navigator . userAgent ) ;
2633+
2634+ if ( isMobile ) {
2635+ console . log ( '📱 Mobile device detected - applying mobile optimizations' ) ;
2636+
2637+ // iOS Safari specific optimizations
2638+ if ( / i P a d | i P h o n e | i P o d / . test ( navigator . userAgent ) ) {
2639+ console . log ( '🍎 iOS Safari optimizations active' ) ;
2640+
2641+ // Prevent iOS Safari zoom on input focus
2642+ document . addEventListener ( 'touchstart' , function ( event ) {
2643+ if ( event . target . tagName === 'INPUT' || event . target . tagName === 'TEXTAREA' ) {
2644+ event . target . style . fontSize = '16px' ;
2645+ }
2646+ } ) ;
2647+
2648+ // Handle iOS Safari viewport changes
2649+ if ( window . visualViewport ) {
2650+ window . visualViewport . addEventListener ( 'resize' , ( ) => {
2651+ setTimeout ( updateMobileViewport , 150 ) ;
2652+ } ) ;
2653+ }
2654+ }
2655+
2656+ // Chrome mobile specific optimizations
2657+ if ( / C h r o m e / . test ( navigator . userAgent ) && / M o b i l e / . test ( navigator . userAgent ) ) {
2658+ console . log ( '🤖 Chrome mobile optimizations active' ) ;
2659+ }
2660+
2661+ // Enhanced resize handling for mobile
2662+ let resizeTimeout ;
2663+ window . addEventListener ( 'resize' , ( ) => {
2664+ clearTimeout ( resizeTimeout ) ;
2665+ resizeTimeout = setTimeout ( ( ) => {
2666+ updateMobileViewport ( ) ;
2667+ // Ensure three.js canvas resizes properly
2668+ camera . aspect = window . innerWidth / window . innerHeight ;
2669+ camera . updateProjectionMatrix ( ) ;
2670+ renderer . setSize ( window . innerWidth , window . innerHeight ) ;
2671+ } , 200 ) ;
2672+ } ) ;
2673+
2674+ // Enhanced orientation change handling
2675+ window . addEventListener ( 'orientationchange' , ( ) => {
2676+ setTimeout ( ( ) => {
2677+ updateMobileViewport ( ) ;
2678+ camera . aspect = window . innerWidth / window . innerHeight ;
2679+ camera . updateProjectionMatrix ( ) ;
2680+ renderer . setSize ( window . innerWidth , window . innerHeight ) ;
2681+
2682+ // Re-check mobile orientation after orientation change
2683+ setTimeout ( ( ) => {
2684+ checkMobileOrientation ( ) ;
2685+ } , 300 ) ;
2686+ } , 300 ) ; // Increased delay for iOS Safari
2687+ } ) ;
2688+
2689+ // Mobile performance optimizations
2690+ document . body . style . cssText += `
2691+ -webkit-font-smoothing: antialiased;
2692+ -moz-osx-font-smoothing: grayscale;
2693+ text-rendering: optimizeLegibility;
2694+ ` ;
2695+
2696+ // Prevent mobile scroll bounce
2697+ document . addEventListener ( 'touchmove' , function ( e ) {
2698+ if ( e . target === document . body || e . target === document . documentElement ) {
2699+ e . preventDefault ( ) ;
2700+ }
2701+ } , { passive : false } ) ;
2702+
2703+ // Enhanced touch event handling
2704+ let touchStartY = 0 ;
2705+ document . addEventListener ( 'touchstart' , function ( e ) {
2706+ touchStartY = e . touches [ 0 ] . clientY ;
2707+ } ) ;
2708+
2709+ document . addEventListener ( 'touchmove' , function ( e ) {
2710+ const touchY = e . touches [ 0 ] . clientY ;
2711+ const touchYDelta = touchStartY - touchY ;
2712+ const el = e . target ;
2713+
2714+ // Allow scrolling only in scrollable elements
2715+ if ( ! el . closest ( '.overlay-menu, .menu-container, .install-instructions, .leaderboard-list' ) ) {
2716+ e . preventDefault ( ) ;
2717+ }
2718+ } , { passive : false } ) ;
2719+ }
2720+
2721+ console . log ( '✅ Mobile support initialization complete' ) ;
2722+ }
25762723} ) ;
25772724
25782725// Also update viewport when DOM is ready
0 commit comments