2025-11-10
#Tech

IEM Past Cars From Blender to Browser

3D web experiences are becoming the gold standard for high-end product showcases. Recently, I built a cinematic, interactive car showcase for Illini Electric Motorsports, using React Three Fiber (R3F), GSAP, and Tailwind CSS.

Here is a technical breakdown of how I solved the biggest challenges in Web3D, from model optimization to buttery-smooth performance.

🛠️ The Stack

  • React Three Fiber (R3F): The renderer.
  • Drei: Essential helpers (Environment, GLTFLoader).
  • React Postprocessing: For that cool "Outline" glow.
  • GSAP: For precision camera control.
  • Tailwind CSS: For the UI overlay.

1. Model Preparation

The Key: "Dimension Reduction" in Blender.

  1. Merge Meshes: I combined thousands of tiny screws and internal parts into a single Background_Parts mesh.
  2. Draco Compression: This is non-negotiable. I reduced the model size from 43MB to ~3MB using Draco.
  3. Texture Optimization: Resized textures to 2K/1K max.

2. Setting the Stage (Lighting & Effects)

In R3F, we aren't just coders; we are photographers.

<Canvas shadows camera={{ position: [0, -100, 30], fov: 50 }}>
  {/* Studio Lighting */}
  <directionalLight intensity={8} castShadow />
  <Environment preset="studio" />
 
  {/* Post-Processing: The "Tron" Look */}
  <Selection>
    <EffectComposer autoClear={false}>
      <Outline visibleEdgeColor={0xffffff} edgeStrength={50} />
    </EffectComposer>
    <CarModel />
  </Selection>
</Canvas>

I used <Environment> for realistic carbon-fiber reflections and <Outline> to give selected parts a distinct, technical highlight.

3. "Focus Mode" Material System

When a user selects a part (e.g., the Diffuser), I wanted an "X-Ray" focus effect: Highlight the target, fade the rest.

Instead of complex shaders, I used dynamic React props:

const getMaterialProps = (partName) => {
  const isHighlighted = activePart === partName;
  const anyActive = activePart !== null;
 
  return {
    // If something is active, but it's not ME, go transparent
    transparent: anyActive && !isHighlighted,
    opacity: anyActive && !isHighlighted ? 0.15 : 1.0,
    depthWrite: !anyActive || isHighlighted, // Prevents Z-fighting
  };
};

4. Cinematic Camera Movement (GSAP)

Default OrbitControls feel manual. I wanted the camera to fly to the specific part automatically.

The Challenge: React state updates vs. Three.js World Matrix updates.

// Inside useEffect
setTimeout(() => {
    const worldCenter = new THREE.Vector3();
    partRef.current.getWorldPosition(worldCenter);
 
    // Animate Camera
    gsap.to(camera.position, {
        x: worldCenter.x + offset.x,
        y: worldCenter.y + offset.y,
        z: worldCenter.z + offset.z,
        duration: 1.5,
        ease: 'power3.inOut'
    });
}, 0);

Conclusion

Building high-performance Web3D is a balancing act between visual fidelity and browser constraints. By optimizing assets in Blender, managing state smartly in React, and using CSS tricks to keep the GPU happy, we created an experience that feels like a native app.

CC BY-SA 4.0

This article is licensed under CC BY-SA 4.0. You are free to share and adapt this work, provided you attribute Kevin Zhong and distribute under the same license.