DEV Community

Cover image for Building a Realistic 3D Monitor with Reflections and HTML Interface using React Three Fiber
A0mineTV
A0mineTV

Posted on

Building a Realistic 3D Monitor with Reflections and HTML Interface using React Three Fiber

Ever wanted to create stunning 3D visualizations that feel truly interactive? Today, we'll build a photorealistic 3D monitor with dynamic reflections and an HTML interface overlay using React Three Fiber and @react-three/drei.

🎯 What We'll Build

By the end of this tutorial, you'll have:

  • βœ… A 3D monitor model with realistic reflections
  • βœ… Smooth presentation controls for interaction
  • βœ… HTML interface overlay on the screen
  • βœ… Professional lighting and shadows
  • βœ… Full-screen immersive experience

πŸš€ Getting Started

Prerequisites

  • Basic React knowledge
  • Node.js installed
  • A GLTF/GLB 3D model (we'll use Monitor.glb)

Installation

npm create vite@latest 3d-monitor-demo -- --template react cd 3d-monitor-demo npm install @react-three/fiber @react-three/drei npm run dev 
Enter fullscreen mode Exit fullscreen mode

πŸ“ Project Structure

src/ β”œβ”€β”€ App.jsx # Main 3D scene β”œβ”€β”€ App.css # Styling for interface └── main.jsx # Entry point public/ └── Monitor.glb # Your 3D model 
Enter fullscreen mode Exit fullscreen mode

πŸ–₯️ Setting Up the Full-Screen Canvas

First, let's create an immersive full-screen experience:

src/App.css

#root { max-width: 100vw; margin: 0; padding: 0; text-align: center; height: 100vh; overflow: hidden; } .canvas-container { width: 100vw; height: 100vh; position: fixed; top: 0; left: 0; } .annotation { background: rgba(0, 0, 0, 0.8); color: white; padding: 8px 12px; border-radius: 6px; font-family: 'Arial', sans-serif; font-size: 12px; font-weight: bold; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.1); } 
Enter fullscreen mode Exit fullscreen mode

🎬 Building the 3D Scene

src/App.jsx

import './App.css' import { Canvas } from '@react-three/fiber' import { PresentationControls, ContactShadows, Environment, useGLTF, Html, CubeCamera } from '@react-three/drei' function App() { return ( <div className="canvas-container"> <Canvas shadows camera={{ position: [0, 0, 20], fov: 35 }}> <ambientLight intensity={0.5} /> <spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} shadow-mapSize={2048} castShadow /> {/* CubeCamera for realistic reflections */} <CubeCamera resolution={512} frames={2} near={0.1} far={1000}> {(texture) => ( <PresentationControls global config={{ mass: 2, tension: 500 }} snap={{ mass: 4, tension: 1500 }} rotation={[0, 0.3, 0]} polar={[-Math.PI / 3, Math.PI / 3]} azimuth={[-Math.PI / 1.4, Math.PI / 2]}> <Monitor rotation={[0, Math.PI, 0]} position={[0, 0, 0]} scale={5} envMapTexture={texture} /> </PresentationControls> )} </CubeCamera> <ContactShadows position={[0, -3, 0]} opacity={0.75} scale={15} blur={3} far={4} /> <Environment preset="city" /> </Canvas> </div> ) } export default App 
Enter fullscreen mode Exit fullscreen mode

πŸ”§ Creating the Monitor Component

The magic happens in our Monitor component where we combine GLTF loading, reflections, and HTML overlays:

function Monitor({ envMapTexture, ...props }) { const { nodes, materials } = useGLTF('/Monitor.glb') return ( <group {...props} dispose={null}> {/* Render all meshes with smart material detection */} {Object.entries(nodes).map(([key, node]) => { if (node.geometry) { // Detect screen elements for special treatment const isScreen = key.toLowerCase().includes('screen') || key.toLowerCase().includes('display'); return ( <mesh key={key} castShadow receiveShadow geometry={node.geometry} material={ isScreen ? ( // Reflective material for screen <meshStandardMaterial envMap={envMapTexture} metalness={0.9} roughness={0.1} color="#000" /> ) : ( // Original materials for other parts node.material || materials[Object.keys(materials)[0]] ) } /> ) } return null })} {/* HTML annotation positioned next to monitor */} <Html scale={0.3} rotation={[0, -Math.PI, 0]} position={[1, 0, 0]} transform> <div className="annotation"> Monitor 3D πŸ–₯️ </div> </Html> </group> ) } 
Enter fullscreen mode Exit fullscreen mode

✨ Key Features Explained

πŸͺž CubeCamera for Reflections

The CubeCamera captures the environment in real-time, creating realistic reflections on the monitor screen:

<CubeCamera resolution={512} frames={2} near={0.1} far={1000}> {(texture) => ( // Your 3D content here receives the reflection texture )} </CubeCamera> 
Enter fullscreen mode Exit fullscreen mode

Parameters:

  • resolution={512}: Good balance between quality and performance
  • frames={2}: Perfect for static scenes (updates every 2 frames)
  • The texture is automatically passed to your components
<PresentationControls global // Mouse controls work globally config={{ mass: 2, tension: 500 }} // Physics-based movement snap={{ mass: 4, tension: 1500 }} // Snap-back behavior rotation={[0, 0.3, 0]} // Initial rotation polar={[-Math.PI / 3, Math.PI / 3]} // Vertical rotation limits azimuth={[-Math.PI / 1.4, Math.PI / 2]} // Horizontal rotation limits > 
Enter fullscreen mode Exit fullscreen mode

🎯 Smart Material Detection

Automatically applies reflective materials to screen elements:

const isScreen = key.toLowerCase().includes('screen') || key.toLowerCase().includes('display'); // Apply reflective material only to screen parts material={ isScreen ? ( <meshStandardMaterial envMap={envMapTexture} metalness={0.9} // High metalness for reflection roughness={0.1} // Low roughness for mirror-like surface color="#000" /> ) : ( node.material // Keep original materials for other parts ) } 
Enter fullscreen mode Exit fullscreen mode

🎨 Bonus: HTML Interface Overlay (Optional)

Note: This section is optional! The core 3D monitor with reflections works perfectly without any HTML overlay. Add this only if you want interactive content on the screen.

If you want to add interactive HTML content directly on the monitor screen, you can overlay HTML elements:

{/* Optional: HTML interface positioned on screen */} <Html scale={0.08} rotation={[0, -Math.PI, 0]} position={[0, 0, 0.8]} transform distanceFactor={5} > <div className="screen-interface"> <div className="status-bar"> <span className="time">14:32</span> <span className="battery">πŸ”‹ 85%</span> </div> <div className="desktop"> <div className="app-icon">πŸ“</div> <div className="app-icon">🎡</div> <div className="app-icon">πŸ“§</div> <div className="app-icon">βš™οΈ</div> </div> <div className="taskbar"> <div className="start-button">πŸͺŸ Start</div> <div className="running-apps"> <span className="app">Chrome</span> <span className="app">VSCode</span> </div> </div> </div> </Html> 
Enter fullscreen mode Exit fullscreen mode

If you choose to add this overlay, include the CSS:

.screen-interface { width: 800px; height: 500px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 8px; display: flex; flex-direction: column; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; overflow: hidden; box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.2); border: 2px solid #333; } .app-icon { width: 60px; height: 60px; background: rgba(255, 255, 255, 0.2); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px; cursor: pointer; transition: all 0.3s ease; backdrop-filter: blur(10px); } .app-icon:hover { background: rgba(255, 255, 255, 0.3); transform: translateY(-2px); } 
Enter fullscreen mode Exit fullscreen mode

🎭 Alternative Screen Content Ideas:

Instead of a full desktop interface, you could add simpler content:

// Simple logo or text on screen <Html scale={0.1} position={[0, 0, 0.5]} transform> <div style={{ color: 'white', fontSize: '24px', fontWeight: 'bold', textAlign: 'center' }}> Welcome to 3D Web </div> </Html> // Or a video element <Html scale={0.08} position={[0, 0, 0.5]} transform> <video width="400" height="300" autoPlay loop muted src="/demo-video.mp4" /> </Html> 
Enter fullscreen mode Exit fullscreen mode

Why you might skip the HTML overlay:

  • βœ… Simpler setup - Focus on the 3D aspects
  • βœ… Better performance - Less DOM manipulation
  • βœ… Cleaner aesthetics - Let the reflections shine
  • βœ… More realistic - Real monitors don't float interfaces

πŸŽͺ Performance Tips

  1. Optimize CubeCamera: Use frames={2} for static scenes
  2. Resolution balance: 512px is usually sufficient for reflections
  3. Conditional rendering: Only apply expensive materials where needed
  4. LOD: Consider using Level of Detail for complex models

πŸ› οΈ Finding 3D Models

You'll need a GLTF/GLB 3D model to follow this tutorial. Here are the best sources for high-quality 3D monitor models:

πŸ”₯ Top Free Sources:

1. Sketchfab

  • Search terms: "monitor", "computer screen", "display", "LCD monitor"
  • Pros: Huge collection, preview in 3D before download
  • License: Check individual model licenses (CC, free for personal use)
  • Example searches:

2. Poly Haven

  • Pros: CC0 license (completely free), high quality
  • Cons: Smaller selection, but excellent quality
  • Perfect for: Professional projects

3. Kenney Assets

  • Pros: Game-ready models, consistent style
  • Search: Office/Electronics section
  • License: CC0 (free for any use)

4. Google Poly Archive (Poly Pizza)

  • Pros: Archive of Google's 3D models
  • Search terms: "monitor", "computer", "screen"
  • License: Various, check individual models

πŸ’Ž Premium Sources (Paid):

1. TurboSquid

  • Best for: Professional, detailed models
  • Price range: $5-$200+
  • Search: "computer monitor GLTF" or "monitor GLB"

2. CGTrader

  • Pros: Good variety, competitive prices
  • Formats: Always check GLTF/GLB availability

3. Fab (Epic Games Store)

  • Pros: High-quality game assets
  • Integration: Works well with Unreal/Unity workflows

🎯 Specific Monitor Model Recommendations:

# Example searches that work well: "Dell monitor GLTF" "Apple monitor 3D model" "Gaming monitor free download" "Computer screen GLB" "LCD display 3D" 
Enter fullscreen mode Exit fullscreen mode

πŸ”§ Model Requirements for This Tutorial:

When choosing a monitor model, ensure it has:

  • βœ… GLTF/GLB format (not OBJ, FBX, or other formats)
  • βœ… Reasonable polygon count (under 50k triangles for web)
  • βœ… Proper naming (ideally with "screen" or "display" in mesh names)
  • βœ… Good UVs (for textures and materials)

πŸ“₯ How to Download and Prepare:

  1. Download your chosen model
  2. Place the .glb file in your public/ folder
  3. Rename it to Monitor.glb or update the code path
  4. Test by checking browser console for loading errors

πŸ” Alternative: Create Your Own Simple Monitor

If you can't find the perfect model, you can create a basic one using:

// Simple monitor using basic geometries function SimpleMonitor() { return ( <group> {/* Monitor stand */} <mesh position={[0, -1, 0]}> <cylinderGeometry args={[0.3, 0.3, 0.1, 8]} /> <meshStandardMaterial color="#333" /> </mesh> {/* Monitor body */} <mesh position={[0, 0, -0.1]}> <boxGeometry args={[4, 2.5, 0.2]} /> <meshStandardMaterial color="#222" /> </mesh> {/* Screen */} <mesh position={[0, 0, 0]}> <boxGeometry args={[3.6, 2.1, 0.01]} /> <meshStandardMaterial color="#000" metalness={0.9} roughness={0.1} /> </mesh> </group> ) } 
Enter fullscreen mode Exit fullscreen mode

πŸš€ Pro Tips for Model Selection:

  • File size: Keep under 10MB for web performance
  • Complexity: More details = better visuals but slower loading
  • Licensing: Always check commercial use permissions
  • Preview: Use Sketchfab's 3D viewer to inspect before download
  • Backup options: Download 2-3 models in case one doesn't work

🎯 Next Steps

  • Animations: Add model animations with useAnimations
  • Physics: Integrate @react-three/cannon for physics
  • VR Support: Add @react-three/xr for VR experiences
  • Post-processing: Use @react-three/postprocessing for effects

πŸ”— Resources

πŸŽ‰ Conclusion

You've just created a stunning 3D monitor visualization with:

  • βœ… Realistic reflections using CubeCamera
  • βœ… Smooth interactive controls
  • βœ… HTML interface overlays
  • βœ… Professional lighting and shadows

The combination of React Three Fiber and @react-three/drei makes creating complex 3D experiences surprisingly straightforward. The declarative React approach to 3D graphics opens up endless possibilities for web applications.

Top comments (0)