Stop Building Boring Menus! This 3D Ship Selector Changes Everything
Stop Building Boring Menus! This 3D Ship Selector Changes Everything
Your game menu is killing your player's first impression. Flat. Static. Forgettable. Meanwhile, indie developers are building 3D ship selection interfaces so gorgeous they belong in AAA studios—and they're doing it with JavaScript.
Here's the painful truth: you've spent months perfecting gameplay mechanics, but players judge your game in the first seven seconds. That loading screen. That character select. That boring grid of thumbnails you copied from a 2015 Unity tutorial. What if your ship selection page didn't just display options—what if it performed?
Enter ship-selection-page by Christian Ortiz, the companion repository for his viral "Laser Drift: Neon Blast" tutorial series. This isn't another generic React component. It's a wireframe-revealing, particle-bursting, sound-reactive 3D experience built with React Three Fiber, Next.js 14, and GSAP animations that will make players feel the power of each ship before they even click.
Ready to abandon flat design forever? Let's dissect how this repository achieves the impossible: browser-native 3D that feels like a native game engine.
What Is ship-selection-page? The Secret Weapon Behind Laser Drift
ship-selection-page is the open-source companion repository for Laser Drift: Neon Blast—a web-based 3D shooting game dripping with vaporwave aesthetics and hand-tracking controls. Created by Christian Ortiz (@cortizdev), this repository captures the exact ship selection interface used in production, complete with custom wireframe reveal animations, particle backgrounds, and reactive sound design.
But here's why it's trending right now: it bridges the gap between web development and game development.
Traditionally, 3D menus required Unity, Unreal, or custom WebGL engines with steep learning curves. Ortiz proved you can achieve production-grade 3D UI using familiar React patterns, declarative Three.js components via React Three Fiber, and modern Next.js deployment. The repository isn't just code—it's a 3-part YouTube masterclass breaking down AI-assisted concept art, 3D modeling pipelines, GLB texture baking, and advanced animation techniques.
The vaporwave aesthetic isn't accidental. Every neon pulse, every wireframe flicker, every synthwave particle serves functional communication: ship stats feel tangible, rarity feels valuable, selection feels ceremonial. This is emotional UI design backed by technical precision.
For React developers eyeing game development, this repository is a gateway drug. For game developers considering web deployment, it's a production blueprint. And for anyone building product configurators, portfolio showcases, or immersive e-commerce experiences? It's pure gold.
Key Features That Make This Repository Insane
Let's dissect the technical architecture that separates this from amateur Three.js experiments:
1. Custom Wireframe Reveal Animation
Most 3D models load with crude progress bars or jarring pop-ins. Ortiz engineered a procedural wireframe-to-solid transition using custom shaders and GSAP timelines. Ships materialize from glowing edge-structures, building anticipation before revealing their final textured form. This isn't cosmetic fluff—it's progressive disclosure that masks loading states while creating narrative drama.
2. React Three Fiber Declarative 3D
Instead of imperative Three.js boilerplate, the entire scene uses JSX-based 3D components. Lights, cameras, meshes, and post-processing effects compose like standard React props. This means hot-reloading 3D scenes, reusable component patterns, and seamless state integration between your UI overlay and 3D viewport.
3. @react-three/postprocessing Pipeline
The repository implements bloom, chromatic aberration, and noise effects through React Three Fiber's postprocessing ecosystem. These aren't slapped-on filters—they're calibrated to the vaporwave palette, with neon elements bleeding light realistically while maintaining UI readability.
4. GSAP-Powered Transition Orchestration
Ship selection isn't a simple model swap. It's a choreographed sequence: camera dolly, particle burst, stat panel slide, description fade, and audio trigger—all synchronized through GSAP timelines with precise easing curves. The result feels intentionally cinematic, not mechanically functional.
5. Particle Background System
A custom InterfaceBackground component generates procedural particle fields that respond to selection state. These aren't decorative—they create spatial depth cues that make the 3D viewport feel infinite, solving the "cardboard diorama" problem plaguing many WebGL implementations.
6. Sound Effects Integration
The SoundEffects component proves audio is non-negotiable for 3D immersion. Each interaction triggers contextually-appropriate synthesized effects, spatialized to match camera position. Web Audio API integration means zero external dependencies for basic deployment.
4 Brutal Real-World Problems This Repository Solves
Problem 1: "My 3D Configurator Feels Like a PowerPoint Slide"
E-commerce sites dumping GLB viewers into generic divs see 60% bounce rates. The wireframe reveal and particle systems here create emotional investment before product details appear. Apply this pattern to furniture, automotive, or fashion configurators.
Problem 2: "React and Three.js Don't Play Nice"
State synchronization between React's render cycle and Three.js's animation loop is a classic nightmare. This repository demonstrates @react-three/fiber's reconciler solving this elegantly—useState hooks driving 3D transforms without performance collapse.
Problem 3: "My Game Menu Needs a Downloaded Engine"
Laser Drift proves browser-based distribution for polished experiences. No Steam approval. No app store gatekeeping. Ship this as a PWA and players have instant access with GPU-accelerated 3D.
Problem 4: "I Can't Afford a 3D Technical Artist"
The YouTube series reveals AI-assisted concept-to-model pipelines using accessible tools. The repository includes optimized GLB assets with baked textures—study the public/glb/ structure to understand production-ready 3D asset delivery.
Step-by-Step Installation & Setup Guide
Ready to run this locally? Follow these exact commands from the repository:
Prerequisites
- Node.js 18+ (required for Next.js 14 App Router features)
- npm or yarn package manager
- Git for cloning
Complete Installation
# Clone the repository from GitHub
git clone https://github.com/cortiz2894/ship-selection-page.git
# Navigate into the project directory
cd ship-selection-page
# Install all dependencies (React Three Fiber, GSAP, Next.js, etc.)
npm install
# Start the development server with hot reloading
npm run dev
Verification
Open your browser to http://localhost:3000. You should see the ship selection interface with:
- A 3D platform with your first ship model
- Working mouse/touch rotation controls
- Initial particle background effects
Environment Configuration (Advanced)
For production builds or custom deployments:
# Create optimized production build
npm run build
# Start production server
npm start
The project uses Next.js 14 App Router, so ensure your next.config.js handles static export if deploying to edge hosts:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
// Required for Three.js GLB loading in static builds
images: {
unoptimized: true,
},
}
module.exports = nextConfig
Audio System Setup
The SoundEffects component expects audio files in public/audio/. For local development without assets, the component gracefully degrades—check browser console for missing file warnings.
REAL Code Examples From the Repository
Let's examine actual patterns from the codebase, adapted for clarity:
Example 1: Project Structure & Component Architecture
The repository follows domain-driven component organization critical for 3D React applications:
├── app/ # Next.js app router with layout.tsx
├── components/
│ ├── ShipSelection/ # Core feature domain
│ │ ├── BaseModel/ # 3D platform all ships rest on
│ │ ├── Ships/ # Individual GLB model wrappers
│ │ ├── ShipGrid/ # Selection carousel/grid logic
│ │ ├── ShipStats/ # Data visualization overlay
│ │ └── ShipDescription/# Lore/flavor text panels
│ ├── WireframeReveal/ # THE secret sauce - custom shader animation
│ ├── InterfaceBackground/# Particle system manager
│ └── SoundEffects/ # Web Audio API integration
├── public/
│ ├── glb/ # Optimized Draco-compressed models
│ └── audio/ # OGG/MP3 dual-format assets
└── constants/ # Ship stat definitions, color palettes
Why this matters: Separating WireframeReveal from Ships means any model gets the reveal animation via composition, not inheritance. The constants/ directory centralizes game balance data—critical when designers tweak stats without touching 3D code.
Example 2: Installation Commands (From README)
# Clone the repository
git clone https://github.com/cortiz2894/ship-selection-page.git
# Navigate to the project
cd ship-selection-page
# Install dependencies
npm install
# Run the development server
npm run dev
Critical insight: The npm install pulls @react-three/fiber@8.x, @react-three/drei@9.x, and three@0.160.x with strict version compatibility. Don't arbitrarily upgrade—Three.js minor versions frequently break GLTF loading.
Example 3: Conceptual React Three Fiber Scene Structure
Based on the tech stack and component organization, the ship selection scene likely implements this pattern:
// Conceptual structure matching repository architecture
import { Canvas } from '@react-three/fiber'
import { OrbitControls, Environment, ContactShadows } from '@react-three/drei'
import { EffectComposer, Bloom, ChromaticAberration } from '@react-three/postprocessing'
import { Ship } from './components/ShipSelection/Ships'
import { WireframeReveal } from './components/WireframeReveal'
import { InterfaceBackground } from './components/InterfaceBackground'
export default function ShipSelectionScene() {
const [selectedShip, setSelectedShip] = useState(0)
return (
<div className="w-full h-screen bg-black">
{/* React Three Fiber Canvas - the 3D viewport */}
<Canvas
camera={{ position: [0, 2, 5], fov: 45 }}
gl={{ antialias: true, alpha: false }}
dpr={[1, 2]} // Responsive pixel ratio for performance
>
{/* Lighting setup for vaporwave aesthetic */}
<ambientLight intensity={0.2} />
<pointLight position={[10, 10, 10]} color="#ff00ff" intensity={2} />
<pointLight position={[-10, -10, -5]} color="#00ffff" intensity={2} />
{/* The platform all ships display on */}
<BaseModel />
{/* Current ship with wireframe reveal animation */}
<WireframeReveal trigger={selectedShip}>
<Ship modelPath={`/glb/ship-${selectedShip}.glb`} />
</WireframeReveal>
{/* Particle background for depth */}
<InterfaceBackground shipIndex={selectedShip} />
{/* Post-processing effects stack */}
<EffectComposer>
<Bloom intensity={1.5} luminanceThreshold={0.2} />
<ChromaticAberration offset={[0.002, 0.002]} />
</EffectComposer>
{/* Camera controls with constraints */}
<OrbitControls
enablePan={false}
minDistance={3}
maxDistance={8}
minPolarAngle={Math.PI / 4}
maxPolarAngle={Math.PI / 2}
/>
</Canvas>
{/* HTML overlay for stats and descriptions */}
<ShipStats shipId={selectedShip} />
<ShipDescription shipId={selectedShip} />
<ShipGrid onSelect={setSelectedShip} active={selectedShip} />
</div>
)
}
Key techniques demonstrated:
dpr={[1, 2]}caps pixel ratio for performance on high-DPI mobile devicesEffectComposerwraps the scene in post-processing without imperative Three.js setup- HTML overlays outside
<Canvas>use standard React—nodomElementmanipulation needed
Example 4: GSAP Animation Integration Pattern
The wireframe reveal likely uses this GSAP + React Three Fiber pattern:
import { useRef, useEffect } from 'react'
import { useFrame } from '@react-three/fiber'
import gsap from 'gsap'
export function WireframeReveal({ children, trigger }) {
const meshRef = useRef()
const materialRef = useRef()
useEffect(() => {
// Reset to wireframe state
materialRef.current.wireframe = true
materialRef.current.opacity = 0.3
// Orchestrated reveal timeline
const tl = gsap.timeline()
// Phase 1: Wireframe pulse
tl.to(materialRef.current, {
opacity: 0.8,
duration: 0.4,
ease: "power2.in"
})
// Phase 2: Solidify with color flash
.to(materialRef.current, {
wireframe: false,
opacity: 1,
duration: 0.6,
ease: "elastic.out(1, 0.5)"
})
// Phase 3: Subtle float for "alive" feeling
.to(meshRef.current.position, {
y: 0.1,
duration: 2,
repeat: -1,
yoyo: true,
ease: "sine.inOut"
})
return () => tl.kill() // Cleanup prevents memory leaks
}, [trigger]) // Re-run when ship changes
return (
<group ref={meshRef}>
{children}
</group>
)
}
Why GSAP over R3F's useFrame: GSAP provides timeline sequencing, easing libraries, and proper cleanup that becomes unmaintainable with raw requestAnimationFrame logic. The trigger dependency ensures animations restart cleanly on ship swaps.
Advanced Usage & Best Practices
Performance Optimization for Production
- Draco compression: Ensure all GLB files use Draco—check
public/glb/file sizes. Uncompressed models crash mobile browsers. - Texture atlasing: The repository's "GLB Bake Texture" tutorial (Part 2) demonstrates combining materials to reduce draw calls.
- LOD (Level of Detail): For your own expansion, implement
@react-three/drei'suseGLTFwith LOD variants for distant ships.
State Management Architecture
The component structure suggests Zustand or Context for ship selection state—avoid prop-drilling through 3D scenes. Keep UI state (hovered stat) separate from 3D state (camera position) to prevent unnecessary re-renders.
Accessibility in 3D
Don't abandon a11y for spectacle. Implement:
- Keyboard navigation for ship grid (
Tab+Enter) aria-liveregions announcing selection changes- Reduced motion media query disabling particle effects
Audio Performance
The Web Audio API can cause garbage collection stutters. Pool audio nodes, use AudioBufferSourceNode recycling, and implement audio suspension when tab loses focus.
Comparison: Why ship-selection-page Over Alternatives
| Feature | ship-selection-page | Generic Three.js Boilerplate | Unity WebGL Export | Spline Embed |
|---|---|---|---|---|
| React Integration | Native (R3F) | Manual bridge required | Impossible | Limited iframe |
| Deployment | Vercel/Netlify instant | Custom hosting required | Specialized server | Spline hosting |
| Source Access | Full open source | Varies | Closed/proprietary | Closed platform |
| Animation Control | GSAP + R3F hooks | Raw WebGL/Three.js | C# scripting | Visual editor only |
| Bundle Size | ~200KB (tree-shaken) | Manual optimization | 10MB+ WASM | External iframe |
| Learning Curve | React + 3D concepts | Steep WebGL fundamentals | C# + engine | Low (limited depth) |
| Customization | Unlimited | Unlimited | Engine-constrained | Platform-constrained |
| Production Example | Laser Drift live game | Rare | Common | Marketing sites |
Verdict: For React developers building interactive 3D experiences with full code ownership, this repository's stack is unmatched. Unity WebGL wins for complex gameplay, but loses on iteration speed and web-native integration.
FAQ: Your Burning Questions Answered
Q: Can I use this with vanilla React, or is Next.js 14 required? The repository uses Next.js 14 App Router for SSR and image optimization, but React Three Fiber works in any React environment. You'll lose automatic static optimization—handle GLB loading paths manually.
Q: How do I swap in my own 3D models?
Export GLB/GLTF from Blender with baked textures (tutorial Part 2 covers this). Place in public/glb/, update constants/shipData.ts with new paths and stats. The WireframeReveal component applies automatically.
Q: Is this performant on mobile devices?
With dpr={[1, 2]}, Draco compression, and reasonable polygon counts (under 50K per ship), yes. Test on actual devices—simulators lie about WebGL performance.
Q: Can I extract just the wireframe animation for my project?
Absolutely. The WireframeReveal component is self-contained. Study its GSAP timeline structure, adapt the shader uniforms for your materials, and compose around any mesh.
Q: Do I need to credit Laser Drift commercially? The license specifies "learning purposes." Contact Christian Ortiz directly for commercial licensing, or treat this as educational reference for building your own implementation.
Q: How does this compare to @react-three/fiber's official examples? Official examples demonstrate isolated techniques. This repository shows production integration: state management, audio, UI overlays, and deployment optimization working together.
Q: What's the minimum Three.js knowledge needed? Basic scene graph understanding (meshes, materials, cameras). R3F abstracts most imperative Three.js code. Follow the 3-part YouTube series for guided fundamentals.
Conclusion: Your 3D UI Revolution Starts Now
The ship-selection-page repository isn't just a cool demo—it's proof that web technologies have matured for serious interactive experiences. Christian Ortiz didn't just build a menu; he built a statement about what's possible when React's component model meets Three.js's rendering power.
The vaporwave aesthetic will date, but the architectural patterns here are timeless: declarative 3D composition, animation-driven state transitions, and performance-conscious asset delivery. Whether you're building game UIs, product configurators, or immersive portfolios, these techniques transfer directly.
My honest take? Clone this repository tonight. Run it locally. Tweak a ship stat, break a particle setting, feel the code respond. Then watch the 3-part YouTube series to understand why every decision was made. That's how you level up—not by reading, but by building alongside masters.
The flat web is dead. Long live the dimensional web.
👉 Star the repository on GitHub and start your build. Your players—and your portfolio—will thank you.
Comments (0)
No comments yet. Be the first to share your thoughts!