← Blurr Motion gallery-r3f-island-minimal
Categorie galleries Tier 3 Techniek #44 Deps three (via esm.sh)

Motion Lab / Galleries / r3f island / minimal

Restrained motion. One object. One rotation.

Een low-poly icosahedron in wireframe, traag roterend op een papieren achtergrond. R3F-equivalent in de Mechanisme-tab.

1. Mechanisme — kopieer 1-op-1, geen styling-keuzes
// Mechanisme: gallery-r3f-island-minimal
// Live demo gebruikt vanilla Three.js (lichter dan r3f-bundle).
// React Three Fiber referentie (educatief):
import { Canvas, useFrame } from '@react-three/fiber';
import { useRef } from 'react';
function Shape() {
  const ref = useRef();
  useFrame((_, dt) => { ref.current.rotation.y += dt * 0.25; });
  return (
    <mesh ref={ref}>
      <icosahedronGeometry args={[1.4, 0]} />
      <meshBasicMaterial color="#0A0A0A" wireframe />
    </mesh>
  );
}
export default () => (
  <Canvas camera={{ position:[0,0,5], fov:50 }} dpr={[1,2]}>
    <Shape />
  </Canvas>
);

// --- VANILLA THREE.JS (LIVE) ---
import * as THREE from 'https://esm.sh/three@0.160.0';
const host = document.querySelector('.r3f-island-mount');
const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
const renderer = new THREE.WebGLRenderer({ antialias:true, alpha:true });
renderer.setPixelRatio(Math.min(devicePixelRatio,2));
host.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(50, 1, 0.1, 100);
camera.position.z = 5;
const wire = new THREE.LineSegments(
  new THREE.WireframeGeometry(new THREE.IcosahedronGeometry(1.6, 0)),
  new THREE.LineBasicMaterial({ color: 0x0A0A0A })
);
scene.add(wire);
function fit(){ const r = host.getBoundingClientRect(); renderer.setSize(r.width,r.height,false); camera.aspect = r.width/r.height; camera.updateProjectionMatrix(); }
new ResizeObserver(fit).observe(host); fit();
function tick(){ wire.rotation.x += 0.004; wire.rotation.y += 0.006; renderer.render(scene,camera); requestAnimationFrame(tick); }
if (reduce) renderer.render(scene,camera); else tick();
2. Skeleton — DOM + class-namen, mag herschikken
<!-- Skeleton: gallery-r3f-island-minimal -->
<section class="r3f-island">
  <p class="kicker">Motion Lab / Galleries / r3f island / minimal</p>
  <div class="r3f-island-mount" data-canvas-host>
    <div class="r3f-island-fallback" hidden>
      <!-- SVG-fallback alleen bij WebGL-failure -->
    </div>
  </div>
  <h1 class="title">Restrained motion. One object. One rotation.</h1>
</section>
3. Styling-template — verplicht eigen invulling per merk
/* Styling: gallery-r3f-island-minimal */
:root {
  --block-bg: #F4F1EB;
  --block-fg: #0A0A0A;
  --block-accent: rgba(10,10,10,.4);
}
.r3f-island { min-height: 80vh; background: var(--block-bg); display: grid; place-items: center; }
.r3f-island-mount { position: relative; width: 100%; min-height: 80vh; }
.r3f-island-mount canvas { display: block; width: 100% !important; height: 100% !important; }
.r3f-island-fallback { position: absolute; inset: 0; display: grid; place-items: center; }
.kicker { font-family: 'JetBrains Mono', monospace; font-size: .7rem; letter-spacing: .15em; text-transform: uppercase; color: var(--block-accent); }
.title { font-family: 'Fraunces', Georgia, serif; font-weight: 300; color: var(--block-fg); }