Skip to content

Commit 3e18703

Browse files
committed
show ship
1 parent 2b783fa commit 3e18703

File tree

5 files changed

+80
-49
lines changed

5 files changed

+80
-49
lines changed

src/components/Navbar.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ import {
3131
} from 'lucide-react'
3232
import { ThemeToggle } from './ThemeToggle'
3333
import { SearchButton } from './SearchButton'
34-
const LazyFeedTicker = React.lazy(() =>
35-
import('./FeedTicker').then((m) => ({ default: m.FeedTicker })),
36-
)
34+
// const LazyFeedTicker = React.lazy(() =>
35+
// import('./FeedTicker').then((m) => ({ default: m.FeedTicker })),
36+
// )
3737
import {
3838
Authenticated,
3939
Unauthenticated,
@@ -336,9 +336,20 @@ export function Navbar({ children }: { children: React.ReactNode }) {
336336
</div>
337337
</div>
338338
<div className="hidden xl:flex flex-1 justify-end min-w-0">
339-
<React.Suspense fallback={null}>
340-
<LazyFeedTicker />
341-
</React.Suspense>
339+
<Link
340+
to="/mcp"
341+
className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-md
342+
bg-gradient-to-r from-emerald-600 to-teal-700
343+
hover:from-emerald-500 hover:to-teal-600
344+
text-white text-xs font-medium
345+
shadow-sm hover:shadow-md
346+
transition-all duration-200"
347+
>
348+
<span className="px-1 py-px text-[9px] font-bold bg-white/20 rounded uppercase">
349+
Alpha
350+
</span>
351+
<span>Try TanStack MCP</span>
352+
</Link>
342353
</div>
343354
<div className="flex items-center gap-2">
344355
<div className="hidden min-[750px]:block">{socialLinks}</div>

src/components/game/IslandExplorer.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Main Island Explorer game component
22
// Uses vanilla Three.js engine for better performance
33

4+
import { useState } from 'react'
45
import { VanillaGameScene } from './scene/VanillaGameScene'
56
import { IntroOverlay } from './ui/IntroOverlay'
67
import { GameHUD } from './ui/GameHUD'
@@ -15,12 +16,31 @@ import { CompassIndicator } from './ui/CompassIndicator'
1516
import { GameOverOverlay } from './ui/GameOverOverlay'
1617
import { StatsHUD } from './ui/StatsHUD'
1718

19+
function LoadingOverlay() {
20+
return (
21+
<div className="absolute inset-0 bg-gradient-to-b from-sky-400 to-cyan-600 flex items-center justify-center z-50">
22+
<div className="text-center">
23+
<div className="w-16 h-16 mx-auto mb-4 border-4 border-white/30 border-t-white rounded-full animate-spin" />
24+
<p className="text-white text-lg font-medium">Loading assets...</p>
25+
<p className="text-white/60 text-sm mt-2">
26+
Preparing ocean, boats, and islands
27+
</p>
28+
</div>
29+
</div>
30+
)
31+
}
32+
1833
export default function IslandExplorer() {
34+
const [isLoading, setIsLoading] = useState(true)
35+
1936
return (
2037
<div className="relative w-full h-[calc(100dvh-var(--navbar-height))] bg-sky-500">
38+
{/* Loading overlay */}
39+
{isLoading && <LoadingOverlay />}
40+
2141
{/* 3D Scene */}
2242
<div className="absolute inset-0">
23-
<VanillaGameScene />
43+
<VanillaGameScene onLoadingChange={setIsLoading} />
2444
</div>
2545

2646
{/* Vignette overlay for depth */}

src/components/game/scene/VanillaGameScene.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { useEffect, useRef, useState } from 'react'
22
import { GameEngine } from '../engine/GameEngine'
33

4-
export function VanillaGameScene() {
4+
interface VanillaGameSceneProps {
5+
onLoadingChange?: (loading: boolean) => void
6+
}
7+
8+
export function VanillaGameScene({ onLoadingChange }: VanillaGameSceneProps) {
59
const containerRef = useRef<HTMLDivElement>(null)
610
const engineRef = useRef<GameEngine | null>(null)
711
const [isReady, setIsReady] = useState(false)
@@ -57,17 +61,24 @@ export function VanillaGameScene() {
5761
})
5862
resizeObserver.observe(container)
5963

64+
onLoadingChange?.(true)
6065
engine
6166
.init()
62-
.then(() => engine.start())
63-
.catch((err) => console.error('GameEngine init failed:', err))
67+
.then(() => {
68+
engine.start()
69+
onLoadingChange?.(false)
70+
})
71+
.catch((err) => {
72+
console.error('GameEngine init failed:', err)
73+
onLoadingChange?.(false)
74+
})
6475

6576
return () => {
6677
resizeObserver.disconnect()
6778
engine.dispose()
6879
engineRef.current = null
6980
}
70-
}, [isReady])
81+
}, [isReady, onLoadingChange])
7182

7283
return (
7384
<div ref={containerRef} style={{ width: '100%', height: '100%' }}>

src/routes/_libraries/explore.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ export const Route = createFileRoute('/_libraries/explore')({
3232
},
3333
})
3434

35-
// Loading screen while game assets load
36-
// TODO: Upgrade to themed loading screen with island silhouette
35+
// Loading screen while game JS bundle loads
3736
function LoadingScreen() {
3837
return (
3938
<div className="w-full h-[calc(100dvh-var(--navbar-height))] bg-gradient-to-b from-sky-400 to-cyan-600 flex items-center justify-center">
@@ -42,6 +41,7 @@ function LoadingScreen() {
4241
<p className="text-white text-lg font-medium">
4342
Preparing your voyage...
4443
</p>
44+
<p className="text-white/60 text-sm mt-2">Loading game engine</p>
4545
</div>
4646
</div>
4747
)

src/routes/_libraries/index.tsx

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createFileRoute, Link } from '@tanstack/react-router'
2-
import { useEffect, useState } from 'react'
2+
33
import { Footer } from '~/components/Footer'
44
import { LazySponsorSection } from '~/components/LazySponsorSection'
55
import discordImage from '~/images/discord-logo-white.svg'
@@ -121,13 +121,6 @@ function Index() {
121121
const { recentPosts } = Route.useLoaderData() as {
122122
recentPosts: BlogFrontMatter[]
123123
}
124-
const [showShip, setShowShip] = useState(false)
125-
126-
useEffect(() => {
127-
if (Math.random() < 0.02) {
128-
setShowShip(true)
129-
}
130-
}, [])
131124

132125
return (
133126
<>
@@ -140,34 +133,30 @@ function Index() {
140133
xl:[--ship-x:80px] xl:[--ship-y:2.5rem]
141134
2xl:[--ship-x:90px] 2xl:[--ship-y:3rem]"
142135
>
143-
{showShip && (
144-
<>
145-
{/* Ship behind splash */}
146-
<div className="absolute left-1/3 bottom-[25%] z-0 animate-ship-peek">
147-
<NetlifyImage
148-
src="/images/ship.png"
149-
alt=""
150-
width={80}
151-
height={80}
152-
className="w-16 xl:w-20"
153-
/>
154-
</div>
155-
{/* Invisible clickable ship in front */}
156-
<Link
157-
to="/explore"
158-
className="absolute left-1/3 bottom-[25%] z-20 animate-ship-peek-clickable"
159-
title="Explore TanStack"
160-
>
161-
<NetlifyImage
162-
src="/images/ship.png"
163-
alt="Explore TanStack"
164-
width={80}
165-
height={80}
166-
className="w-16 xl:w-20 opacity-0"
167-
/>
168-
</Link>
169-
</>
170-
)}
136+
{/* Ship behind splash */}
137+
<div className="absolute left-1/3 bottom-[25%] z-0 animate-ship-peek">
138+
<NetlifyImage
139+
src="/images/ship.png"
140+
alt=""
141+
width={80}
142+
height={80}
143+
className="w-16 xl:w-20"
144+
/>
145+
</div>
146+
{/* Invisible clickable ship in front */}
147+
<Link
148+
to="/explore"
149+
className="absolute left-1/3 bottom-[25%] z-20 animate-ship-peek-clickable"
150+
title="Explore TanStack"
151+
>
152+
<NetlifyImage
153+
src="/images/ship.png"
154+
alt="Explore TanStack"
155+
width={80}
156+
height={80}
157+
className="w-16 xl:w-20 opacity-0"
158+
/>
159+
</Link>
171160
<BrandContextMenu className="cursor-pointer relative z-10">
172161
<NetlifyImage
173162
src="/images/logos/splash-light.png"

0 commit comments

Comments
 (0)