Skip to main content
Back to Home
Experiment · 3D Web

Ave Muji Cards

An interactive 3D collectible card experience leveraging a Physically Based Rendering (PBR) pipeline, Three.js, and physics-driven pointer tilt.


This project is an interactive 3D card experiment inspired by physical foil collectibles. The implementation breaks down into three distinct layers: texture asset generation, 3D scene setup (Three.js & React Three Fiber), and physics-driven pointer interactions.

1. The PBR Asset Pipeline

To achieve a realistic embossed gold appearance without building a heavy, high-polygon 3D mesh, the card uses a single flat plane (PlaneGeometry) combined with baked texture maps:

  • Base Map (Albedo): The clean 2D artwork and base coloration without baked shadows.
  • Normal Map: Generated from height and bevel data to give tactile depth to borders, typography, and card contours.
  • Roughness Map: Encodes micro-surface variation. Matte areas scatter light softly, while metallic engravings reflect light sharply.
  • Metalness: Configured directly on the physical material as metalness: 1.0, instructing the shader to treat the card as conductive metallic foil.
Base Map (Albedo) - Mortis
Base Map
Normal Map - Mortis
Normal Map
Roughness Map - Mortis
Roughness Map
Mortis (Mitsumi Wakaba)

2. Three.js / R3F Material & Environment Setup

Metallic surfaces cannot reflect convincing highlights from simple point or directional lights alone. The scene utilizes Three.js's physical shader material combined with Image-Based Lighting (IBL) via an Environment Map (such as <Environment preset="city" />).

As the card rotates, surface normals sample the HDR reflection probe, producing real-time glints across the foil engravings:

jsx
// Texture loader pipeline
const [albedo, normal, roughness] = useTexture([
  '/ticket/albedo.png',
  '/ticket/normal.png',
  '/ticket/roughness.png'
]);

// Material definition
<mesh geometry={ticketGeometry}>
  <meshPhysicalMaterial
    map={albedo}
    normalMap={normal}
    normalScale={[0.6, 0.6]}
    roughnessMap={roughness}
    metalness={1.0}
    roughness={0.8}
    clearcoat={0.3}
    clearcoatRoughness={0.1}
    envMapIntensity={1.5}
  />
</mesh>

3. Pointer-Based 3D Physics and Tilt

The interaction is driven by tracking pointer coordinates relative to the card's bounding box and feeding those values into damped springs or lerped rotations:

  • Normalized Pointer Coordinates: Calculates mouse or touch offset from the center of the card from -1.0 to 1.0.
  • Rotation Clamping: Rotations are clamped (rotation.y = mouseX * maxAngle and rotation.x = -mouseY * maxAngle) to keep perspective natural.
  • Dynamic Light Tracking: A local point light is simultaneously offset to mirror the cursor position, emphasizing normal-mapped highlights directly under the user's cursor.
  • Spring Damping: Adds smooth inertia so the card drifts back to its resting position when the cursor leaves the frame.
  • Mobile Gyroscope: On phones supporting DeviceOrientationEvent, gamma (tilt left/right) and beta - 45° (pitch) map directly to rotation angles, with sensor jitter smoothed via lerp damping.