Skip to content

Instantly share code, notes, and snippets.

@dln
Created February 17, 2025 15:48
Show Gist options
  • Save dln/b49979cc85af7b3f4f371df49b8b75d7 to your computer and use it in GitHub Desktop.
Save dln/b49979cc85af7b3f4f371df49b8b75d7 to your computer and use it in GitHub Desktop.
import * as THREE from 'three';
import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2.js';
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
export function initPenteract(elem) {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(95, elem.clientWidth / elem.clientHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true,
});
renderer.setSize(elem.clientWidth, elem.clientHeight);
elem.appendChild(renderer.domElement);
const verts = [];
for (let i = 0; i < 32; i++) {
const x = (i & 1) ? 1 : -1;
const y = (i & 2) ? 1 : -1;
const z = (i & 4) ? 1 : -1;
const w = (i & 8) ? 1 : -1;
const v = (i & 16) ? 1 : -1;
verts.push([x, y, z, w, v]);
}
const edges = [];
for (let i = 0; i < verts.length; i++) {
for (let j = i + 1; j < verts.length; j++) {
let diffCount = 0;
for (let k = 0; k < 5; k++) {
if (verts[i][k] !== verts[j][k]) {
diffCount++;
}
}
if (diffCount === 1) {
edges.push([i, j]);
}
}
}
const material = new LineMaterial({
transparent: true,
opacity: 0.5,
color: 0x5f6f7f,
linewidth: 1.5,
resolution: new THREE.Vector2(elem.clientWidth, elem.clientHeight)
});
const lines = [];
for (let edge of edges) {
const geometry = new LineGeometry();
geometry.setPositions(new Array(6).fill(0));
const line = new LineSegments2(geometry, material);
lines.push(line);
scene.add(line);
}
camera.position.z = 1.0;
// Projection function
function project5Dto3D(point5D, w, v) {
const scale = 2 / (w - point5D[3]);
const scale2 = 2 / (v - point5D[4]);
return [
point5D[0] * scale * scale2,
point5D[1] * scale * scale2,
point5D[2] * scale * scale2
];
}
let angle = Math.random() * Math.PI * 2;
const rotationSpeed = 0.00025; // radians per frame
function animate() {
requestAnimationFrame(animate);
angle += rotationSpeed;
const proj = verts.map(v => {
// Rotate in XW plane
let x = v[0] * Math.cos(angle) - v[3] * Math.sin(angle);
let w = v[0] * Math.sin(angle) + v[3] * Math.cos(angle);
// Rotate in YZ plane
let y = v[1] * Math.cos(angle * 0.7) - v[2] * Math.sin(angle * 0.7);
let z = v[1] * Math.sin(angle * 0.7) + v[2] * Math.cos(angle * 0.7);
// Rotate in VW plane (5th dimension)
let v5 = v[4] * Math.cos(angle * 0.5) - w * Math.sin(angle * 0.5);
w = v[4] * Math.sin(angle * 0.5) + w * Math.cos(angle * 0.5);
return project5Dto3D([x, y, z, w, v5], 3, 3);
});
lines.forEach((line, i) => {
const start = proj[edges[i][0]];
const end = proj[edges[i][1]];
const positions = [
start[0], start[1], start[2],
end[0], end[1], end[2]
];
line.geometry.setPositions(positions);
});
renderer.render(scene, camera);
}
function handleResize() {
camera.aspect = elem.clientWidth / elem.clientHeight;
camera.updateProjectionMatrix();
renderer.setSize(elem.clientWidth, elem.clientHeight);
material.resolution.set(elem.clientWidth, elem.clientHeight);
}
window.addEventListener('resize', handleResize);
animate();
return () => {
window.removeEventListener('resize', handleResize);
elem.removeChild(renderer.domElement);
renderer.dispose();
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment