Skip to content

Instantly share code, notes, and snippets.

@sperand-io
Created February 4, 2025 04:53
Show Gist options
  • Save sperand-io/650064e3c6d7c8cbcc40d95aa052d27c to your computer and use it in GitHub Desktop.
Save sperand-io/650064e3c6d7c8cbcc40d95aa052d27c to your computer and use it in GitHub Desktop.
coplanar points on a rotating cube
import * as THREE from 'three';
const camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.1,
100
);
camera.position.set(3, 3, 5);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
// A simple ambient & directional light so we can see the highlights:
scene.add(new THREE.AmbientLight(0x888888));
const dirLight = new THREE.DirectionalLight(0xffffff, 0.6);
dirLight.position.set(10, 10, 10);
scene.add(dirLight);
const cubeGroup = new THREE.Group();
scene.add(cubeGroup);
// Create the edges of the cube
const boxGeometry = new THREE.BoxGeometry(2, 2, 2);
const edges = new THREE.EdgesGeometry(boxGeometry);
const edgesMaterial = new THREE.LineBasicMaterial({ color: 0x000000 });
const boxEdges = new THREE.LineSegments(edges, edgesMaterial);
cubeGroup.add(boxEdges);
// Corner positions (box is centered at origin, ±1 in each axis)
const cornerPositions = [
new THREE.Vector3(-1, -1, 1), // 0
new THREE.Vector3(1, -1, 1), // 1
new THREE.Vector3(1, 1, 1), // 2
new THREE.Vector3(-1, 1, 1), // 3
new THREE.Vector3(-1, -1, -1), // 4
new THREE.Vector3(1, -1, -1), // 5
new THREE.Vector3(1, 1, -1), // 6
new THREE.Vector3(-1, 1, -1), // 7
];
// Create a small sphere at each corner
const cornerSpheres = [];
const sphereRadius = 0.07;
const sphereGeometry = new THREE.SphereGeometry(sphereRadius, 16, 16);
cornerPositions.forEach(pos => {
const material = new THREE.MeshPhongMaterial({ color: 0x888888 });
const sphere = new THREE.Mesh(sphereGeometry, material);
sphere.position.copy(pos);
cubeGroup.add(sphere); // Add sphere into the same group
cornerSpheres.push(sphere);
});
// List of coplanar sets (corner indices)
const coplanarSets = [
[0, 1, 2, 3], // front face
[4, 5, 6, 7], // back face
[0, 1, 5, 4], // bottom face
[2, 3, 7, 6], // top face
[0, 3, 7, 4], // left face
[1, 2, 6, 5], // right face
[0, 2, 6, 4], // one diagonal plane
[1, 3, 7, 5], // other diagonal plane
];
let currentSetIndex = 0;
const highlightColor = 0xff00ff;
const neutralColor = 0x888888;
function highlightCoplanarSet() {
// reset all spheres
cornerSpheres.forEach(s => s.material.color.setHex(neutralColor));
// highlight the next 4
coplanarSets[currentSetIndex].forEach(i => {
cornerSpheres[i].material.color.setHex(highlightColor);
});
}
// cycle to next subset every second
setInterval(() => {
currentSetIndex = (currentSetIndex + 1) % coplanarSets.length;
highlightCoplanarSet();
}, 1000);
// start with the first subset highlighted
highlightCoplanarSet();
// --- Animate / render loop ---
function animation() {
window.requestAnimationFrame(animate);
cubeGroup.rotation.x += 0.005;
cubeGroup.rotation.y += 0.01;
renderer.render(scene, camera);
}
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animation);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment