Motion Lab / Heroes / three scene / minimal
// Mechanisme: hero-three-scene-minimal
import * as THREE from 'https://esm.sh/three@0.160.0';
const cv = document.querySelector('.three-canvas-minimal');
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const wrap = cv.parentElement;
const r = new THREE.WebGLRenderer({ canvas: cv, antialias: true, alpha: true });
r.setPixelRatio(Math.min(devicePixelRatio, 2));
r.setSize(wrap.clientWidth, wrap.clientHeight);
const sc = new THREE.Scene();
const cam = new THREE.PerspectiveCamera(45, wrap.clientWidth / wrap.clientHeight, 0.1, 100);
cam.position.z = 3.4;
const mesh = new THREE.Mesh(
new THREE.IcosahedronGeometry(1, 1),
new THREE.MeshBasicMaterial({ color: 0x0a0a0a, wireframe: true })
);
sc.add(mesh);
let mx = 0, my = 0, cx = 0, cy = 0;
window.addEventListener('mousemove', e => { mx = e.clientX / innerWidth - 0.5; my = e.clientY / innerHeight - 0.5; });
function tick() {
cx += (mx - cx) * 0.05; cy += (my - cy) * 0.05;
cam.position.x = cx * 1.2; cam.position.y = -cy * 1.2; cam.lookAt(0, 0, 0);
mesh.rotation.x += 0.0025; mesh.rotation.y += 0.0035;
r.render(sc, cam);
if (!reduce) requestAnimationFrame(tick);
}
tick(); <!-- Skeleton: hero-three-scene-minimal -->
<section class="hero-three">
<div class="hero-three__stage">
<canvas class="three-canvas-minimal"></canvas>
<h1>Design moves forward, always.</h1>
</div>
</section> /* Styling: hero-three-scene-minimal */
:root { --block-bg:#F4F1EB; --block-fg:#0A0A0A; --block-accent:#0A0A0A; }
.hero-three__stage { position: relative; width: 100%; height: 70vh; }
.three-canvas-minimal { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }