Computer-Ag am WvS Blog der Computer-AG am Werner von Siemens Gymnasium Berlin

6. März 2026

6.3.2026

Filed under: Allgemein,Tagesberichte,Termine — admin @ 15:45

Heute ist eine weitere Person der SuS dazu gekommen. Die Forscher:innen-AG hat offenbar auch Zuwachs bekommen. Wir haben ein Auto-Loop-Batch-Script angeschaut.

Notizen: https://fobizz.com/de/

Nächste Mal normal.

12 × K₁₂ — 3D
ziehen zum drehen · scrollen zum zoomen

Claude – Kugeln.

Rotierende Kugeln:

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>32 × K₃₂ — Kreisel</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body { background: #000; overflow: hidden; }
  canvas { display: block; }
  #hint {
    position: fixed; bottom: 16px; left: 50%; transform: translateX(-50%);
    color: rgba(255,255,255,0.18); font: 11px monospace;
    letter-spacing: 0.1em; pointer-events: none; transition: opacity 3s;
  }
</style>
</head>
<body>
<div id="hint">ziehen zum drehen · scrollen zum zoomen</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
(() => {
  const NC = 32;
  const NP = 32;
  const BIG_R = 8.0;
  const SMALL_R = 1.1;

  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 300);
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  renderer.setClearColor(0x000000);
  document.body.appendChild(renderer.domElement);

  function fibSphere(n, radius) {
    const pts = [];
    const golden = Math.PI * (3 - Math.sqrt(5));
    for (let i = 0; i < n; i++) {
      const y = 1 - (i / (n - 1)) * 2;
      const r = Math.sqrt(1 - y * y);
      const theta = golden * i;
      pts.push(new THREE.Vector3(r * Math.cos(theta) * radius, y * radius, r * Math.sin(theta) * radius));
    }
    return pts;
  }

  function hslToRGB(h, s, l) {
    s /= 100; l /= 100;
    const k = n => (n + h / 30) % 12;
    const a = s * Math.min(l, 1 - l);
    const f = n => l - a * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1));
    return new THREE.Color(f(0), f(4), f(8));
  }

  // Gyro for meta sphere: very slow
  function createMetaGyro() {
    return {
      getAxis(t) {
        const tilt = 0.25 + 0.15 * Math.sin(t * 0.004) + 0.08 * Math.sin(t * 0.0025);
        const prec = t * 0.002 + 0.2 * Math.sin(t * 0.0013);
        return new THREE.Vector3(
          Math.sin(tilt) * Math.cos(prec),
          Math.cos(tilt),
          Math.sin(tilt) * Math.sin(prec)
        ).normalize();
      },
      getSpeed(t) {
        return 0.00025 * (1.0 + 0.3 * Math.sin(t * 0.006));
      }
    };
  }

  // Gyro for small spheres: clearly visible rotation, each unique
  function createClusterGyro(seed) {
    const s = seed;
    // Each small sphere gets a distinct base speed
    const base = 0.0015 + (s % 13) * 0.0002;
    return {
      getAxis(t) {
        const tilt = 0.3 + 0.2 * Math.sin(t * (0.006 + s * 0.001) + s * 1.7)
                         + 0.1 * Math.sin(t * (0.004 + s * 0.0007) + s * 0.9);
        const prec = t * (0.004 + s * 0.0005) + 0.3 * Math.sin(t * (0.003 + s * 0.0008) + s * 2.3);
        return new THREE.Vector3(
          Math.sin(tilt) * Math.cos(prec),
          Math.cos(tilt),
          Math.sin(tilt) * Math.sin(prec)
        ).normalize();
      },
      getSpeed(t) {
        return base * (1.0 + 0.25 * Math.sin(t * (0.008 + s * 0.001) + s * 0.7));
      }
    };
  }

  const centers = fibSphere(NC, BIG_R);
  const hues = [];
  for (let i = 0; i < NC; i++) hues.push((i * 360 / NC) % 360);

  const gc = document.createElement('canvas');
  gc.width = 128; gc.height = 128;
  const gx = gc.getContext('2d');
  const gr = gx.createRadialGradient(64, 64, 0, 64, 64, 64);
  gr.addColorStop(0, 'rgba(255,255,255,0.9)');
  gr.addColorStop(0.15, 'rgba(255,255,255,0.3)');
  gr.addColorStop(0.4, 'rgba(255,255,255,0.05)');
  gr.addColorStop(1, 'rgba(255,255,255,0)');
  gx.fillStyle = gr;
  gx.fillRect(0, 0, 128, 128);
  const glowTex = new THREE.CanvasTexture(gc);

  // === Build clusters — each is a pivot group with a spinning inner group ===
  // pivot sits at center position (doesn't rotate)
  // inner group sits at (0,0,0) inside pivot and rotates
  const clusterPivots = [];
  const clusterInners = [];
  const clusterGyros = [];

  for (let ci = 0; ci < NC; ci++) {
    const pivot = new THREE.Group();
    pivot.position.copy(centers[ci]);

    const inner = new THREE.Group();
    pivot.add(inner);

    const h = hues[ci];
    const localPts = fibSphere(NP, SMALL_R);

    // Shell on inner (rotates with it)
    const shellGeo = new THREE.SphereGeometry(SMALL_R, 24, 18);
    const color = hslToRGB(h, 45, 32);
    inner.add(new THREE.Mesh(shellGeo, new THREE.MeshBasicMaterial({
      color, transparent: true, opacity: 0.05, side: THREE.DoubleSide, depthWrite: false
    })));
    inner.add(new THREE.Mesh(shellGeo, new THREE.MeshBasicMaterial({
      color, wireframe: true, transparent: true, opacity: 0.025
    })));

    // Intra lines
    const pos = [];
    for (let i = 0; i < NP; i++)
      for (let j = i + 1; j < NP; j++) {
        pos.push(localPts[i].x, localPts[i].y, localPts[i].z);
        pos.push(localPts[j].x, localPts[j].y, localPts[j].z);
      }
    const lg = new THREE.BufferGeometry();
    lg.setAttribute('position', new THREE.Float32BufferAttribute(pos, 3));
    inner.add(new THREE.LineSegments(lg, new THREE.LineBasicMaterial({
      color: hslToRGB(h, 55, 52), transparent: true, opacity: 0.25
    })));

    // Dots
    const dotGeo = new THREE.SphereGeometry(0.035, 4, 4);
    const dotMat = new THREE.MeshBasicMaterial({ color: hslToRGB(h, 60, 82) });
    for (let i = 0; i < NP; i++) {
      const m = new THREE.Mesh(dotGeo, dotMat);
      m.position.copy(localPts[i]);
      inner.add(m);
    }
    for (let i = 0; i < NP; i += 2) {
      const s = new THREE.Sprite(new THREE.SpriteMaterial({
        map: glowTex, color: hslToRGB(h, 60, 58),
        transparent: true, opacity: 0.12,
        blending: THREE.AdditiveBlending, depthWrite: false
      }));
      s.position.copy(localPts[i]);
      s.scale.set(0.4, 0.4, 1);
      inner.add(s);
    }

    // Center dot (on pivot, doesn't rotate — stays at center)
    pivot.add(new THREE.Mesh(
      new THREE.SphereGeometry(0.14, 10, 10),
      new THREE.MeshBasicMaterial({ color: hslToRGB(h, 55, 80) })
    ));
    const cg = new THREE.Sprite(new THREE.SpriteMaterial({
      map: glowTex, color: hslToRGB(h, 60, 55),
      transparent: true, opacity: 0.5,
      blending: THREE.AdditiveBlending, depthWrite: false
    }));
    cg.scale.set(1.8, 1.8, 1);
    pivot.add(cg);

    clusterPivots.push(pivot);
    clusterInners.push(inner);
    clusterGyros.push(createClusterGyro(ci + 1));
  }

  // === Meta group ===
  const metaGroup = new THREE.Group();

  const metaGeo = new THREE.SphereGeometry(BIG_R, 48, 36);
  metaGroup.add(new THREE.Mesh(metaGeo, new THREE.MeshBasicMaterial({
    color: new THREE.Color(0.15, 0.18, 0.25),
    transparent: true, opacity: 0.04, side: THREE.DoubleSide, depthWrite: false
  })));
  metaGroup.add(new THREE.Mesh(metaGeo, new THREE.MeshBasicMaterial({
    color: new THREE.Color(0.3, 0.35, 0.45),
    wireframe: true, transparent: true, opacity: 0.03, depthWrite: false
  })));
  for (let lat = -2; lat <= 2; lat++) {
    const y = (lat / 3) * BIG_R;
    const ringR = Math.sqrt(BIG_R * BIG_R - y * y);
    const curve = new THREE.EllipseCurve(0, 0, ringR, ringR, 0, Math.PI * 2, false, 0);
    const pts2d = curve.getPoints(80);
    const pts3d = pts2d.map(p => new THREE.Vector3(p.x, y, p.y));
    metaGroup.add(new THREE.LineLoop(
      new THREE.BufferGeometry().setFromPoints(pts3d),
      new THREE.LineBasicMaterial({ color: new THREE.Color(0.4, 0.45, 0.55), transparent: true, opacity: 0.06 })
    ));
  }

  function makeTube(a, b, radius, color, opacity) {
    const dir = new THREE.Vector3().subVectors(b, a);
    const len = dir.length();
    const mid = new THREE.Vector3().addVectors(a, b).multiplyScalar(0.5);
    const geo = new THREE.CylinderGeometry(radius, radius, len, 4, 1);
    const mat = new THREE.MeshBasicMaterial({ color, transparent: true, opacity, depthWrite: false });
    const mesh = new THREE.Mesh(geo, mat);
    mesh.position.copy(mid);
    mesh.lookAt(b);
    mesh.rotateX(Math.PI / 2);
    return mesh;
  }
  for (let i = 0; i < NC; i++) {
    for (let j = i + 1; j < NC; j++) {
      const mixH = (hues[i] + hues[j]) / 2;
      metaGroup.add(makeTube(centers[i], centers[j], 0.06, hslToRGB(mixH, 45, 45), 0.07));
      metaGroup.add(makeTube(centers[i], centers[j], 0.025, hslToRGB(mixH, 50, 55), 0.3));
    }
  }

  clusterPivots.forEach(p => metaGroup.add(p));

  // Meta center
  const metaCenterMat = new THREE.MeshBasicMaterial({
    color: new THREE.Color(1, 1, 1), transparent: true, opacity: 0.6
  });
  metaGroup.add(new THREE.Mesh(new THREE.SphereGeometry(1.0, 24, 24), metaCenterMat));
  const metaGlowMat = new THREE.SpriteMaterial({
    map: glowTex, color: new THREE.Color(1, 1, 1),
    transparent: true, opacity: 0.6,
    blending: THREE.AdditiveBlending, depthWrite: false
  });
  const metaGlowSprite = new THREE.Sprite(metaGlowMat);
  metaGlowSprite.scale.set(14, 14, 1);
  metaGroup.add(metaGlowSprite);
  const metaGlow2Mat = new THREE.SpriteMaterial({
    map: glowTex, color: new THREE.Color(1, 1, 1),
    transparent: true, opacity: 0.2,
    blending: THREE.AdditiveBlending, depthWrite: false
  });
  const metaGlow2Sprite = new THREE.Sprite(metaGlow2Mat);
  metaGlow2Sprite.scale.set(22, 22, 1);
  metaGroup.add(metaGlow2Sprite);

  scene.add(metaGroup);

  const metaGyro = createMetaGyro();

  // === Camera ===
  let isDrag = false, prevM = { x: 0, y: 0 };
  let camRotY = 0, camRotX = 0.3, tCamRotY = 0, tCamRotX = 0.3;
  let dist = 26, tDist = 26;
  const el = renderer.domElement;

  el.addEventListener('mousedown', e => { isDrag = true; prevM = { x: e.clientX, y: e.clientY }; fadeHint(); });
  el.addEventListener('mousemove', e => {
    if (!isDrag) return;
    tCamRotY += (e.clientX - prevM.x) * 0.004;
    tCamRotX += (e.clientY - prevM.y) * 0.004;
    tCamRotX = Math.max(-1.5, Math.min(1.5, tCamRotX));
    prevM = { x: e.clientX, y: e.clientY };
  });
  el.addEventListener('mouseup', () => isDrag = false);
  el.addEventListener('mouseleave', () => isDrag = false);
  el.addEventListener('touchstart', e => { isDrag = true; prevM = { x: e.touches[0].clientX, y: e.touches[0].clientY }; fadeHint(); });
  el.addEventListener('touchmove', e => {
    if (!isDrag) return; e.preventDefault();
    tCamRotY += (e.touches[0].clientX - prevM.x) * 0.004;
    tCamRotX += (e.touches[0].clientY - prevM.y) * 0.004;
    tCamRotX = Math.max(-1.5, Math.min(1.5, tCamRotX));
    prevM = { x: e.touches[0].clientX, y: e.touches[0].clientY };
  }, { passive: false });
  el.addEventListener('touchend', () => isDrag = false);
  el.addEventListener('wheel', e => { tDist += e.deltaY * 0.02; tDist = Math.max(10, Math.min(60, tDist)); fadeHint(); });

  function fadeHint() { document.getElementById('hint').style.opacity = '0'; }

  let time = 0;
  const quat = new THREE.Quaternion();

  function animate() {
    requestAnimationFrame(animate);
    time += 0.008;

    camRotY += (tCamRotY - camRotY) * 0.06;
    camRotX += (tCamRotX - camRotX) * 0.06;
    dist += (tDist - dist) * 0.06;
    camera.position.set(
      dist * Math.cos(camRotX) * Math.sin(camRotY),
      dist * Math.sin(camRotX),
      dist * Math.cos(camRotX) * Math.cos(camRotY)
    );
    camera.lookAt(0, 0, 0);

    // Meta: very slow gyroscopic rotation
    const metaAxis = metaGyro.getAxis(time);
    quat.setFromAxisAngle(metaAxis, metaGyro.getSpeed(time));
    metaGroup.quaternion.multiply(quat);

    // Each small sphere: independent visible rotation
    for (let ci = 0; ci < NC; ci++) {
      const axis = clusterGyros[ci].getAxis(time);
      const speed = clusterGyros[ci].getSpeed(time);
      quat.setFromAxisAngle(axis, speed);
      clusterInners[ci].quaternion.multiply(quat);
    }

    // Iridescent center (slow)
    const h = (time * 3) % 360;
    metaCenterMat.color.copy(hslToRGB(h, 50, 70));
    metaGlowMat.color.copy(hslToRGB(h, 60, 50));
    metaGlow2Mat.color.copy(hslToRGB((h + 60) % 360, 40, 40));

    renderer.render(scene, camera);
  }
  animate();

  window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  });
})();
</script>
</body>
</html>

Keine Kommentare »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment