Test: Difference between revisions

From Open Source Ecology
Jump to navigation Jump to search
No edit summary
No edit summary
 
(61 intermediate revisions by the same user not shown)
Line 1: Line 1:
Hello Friends,
<html>
<div id="ose-3d-mindmap" style="width:100%; height:700px; border:1px solid #ccc; overflow:hidden; position:relative;"></div>


We are having great success with the recently announced OSE Apprenticeship, with 10 people from 6 countries signed up already. So please pass this on to your friends - this is an authentic opportunity to continue working with OSE - with the promise of the Seed Eco-Home as a solid revenue stream as we continue to work on solving pressing world issues. It's
<script src="https://unpkg.com/three@0.160.0/build/three.min.js"></script>
<script src="https://unpkg.com/three@0.160.0/examples/js/controls/OrbitControls.js"></script>


Looks like we have a few workshops coming up in September. Read the description to appreciate an unprecedented flurry of immersion experience where you truly will have the opportunity to learn more practical skills than you would in a lifetime. 3 months of immersion, some impressive builds, and building the OSE facility in Missouri for people to participate year round. Sign up and find more info at https://bit.ly/3wHGWdx. Early-bird registration is extended a few days to 23:59 CST on Thursday, June 3, 2021. True Fans discounts and multiple day discounts are available, and we can also do work exchange for people who can come early and help with prep.
<script>
(function () {
  const container = document.getElementById('ose-3d-mindmap');
  if (!container) return;
 
  const words = [
    "collaborative",
    "design",
    "for",
    "a",
    "transparent",
    "and",
    "inclusive",
    "economy",
    "of",
    "abundance"
  ];
 
  const scene = new THREE.Scene();
  scene.background = new THREE.Color(0xffffff);
 
  const camera = new THREE.PerspectiveCamera(
    50,
    container.clientWidth / container.clientHeight,
    0.1,
    2000
  );
  camera.position.set(0, 0, 260);
 
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio || 1);
  renderer.setSize(container.clientWidth, container.clientHeight);
  container.appendChild(renderer.domElement);
 
  const controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.08;
  controls.rotateSpeed = 0.8;
  controls.zoomSpeed = 0.9;
  controls.panSpeed = 0.7;
 
  const ambient = new THREE.AmbientLight(0xffffff, 1.2);
  scene.add(ambient);
 
  const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
  dirLight.position.set(120, 150, 200);
  scene.add(dirLight);
 
  function makeTextSprite(message) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
 
    const fontSize = 48;
    const paddingX = 28;
    const paddingY = 18;
    ctx.font = 'bold ' + fontSize + 'px Arial';
 
    const textWidth = Math.ceil(ctx.measureText(message).width);
    canvas.width = textWidth + paddingX * 2;
    canvas.height = fontSize + paddingY * 2;
 
    ctx.font = 'bold ' + fontSize + 'px Arial';
    ctx.textBaseline = 'middle';
    ctx.textAlign = 'center';
 
    ctx.fillStyle = 'rgba(255,255,255,0.92)';
    ctx.strokeStyle = 'rgba(40,40,40,0.9)';
    ctx.lineWidth = 3;
    roundRect(ctx, 2, 2, canvas.width - 4, canvas.height - 4, 14, true, true);
 
    ctx.fillStyle = '#111111';
    ctx.fillText(message, canvas.width / 2, canvas.height / 2);
 
    const texture = new THREE.CanvasTexture(canvas);
    texture.needsUpdate = true;
 
    const material = new THREE.SpriteMaterial({
      map: texture,
      transparent: true
    });
 
    const sprite = new THREE.Sprite(material);
 
    const scale = 0.34;
    sprite.scale.set(canvas.width * scale, canvas.height * scale, 1);
 
    return sprite;
  }
 
  function roundRect(ctx, x, y, w, h, r, fill, stroke) {
    if (w < 2 * r) r = w / 2;
    if (h < 2 * r) r = h / 2;
    ctx.beginPath();
    ctx.moveTo(x + r, y);
    ctx.arcTo(x + w, y, x + w, y + h, r);
    ctx.arcTo(x + w, y + h, x, y + h, r);
    ctx.arcTo(x, y + h, x, y, r);
    ctx.arcTo(x, y, x + w, y, r);
    ctx.closePath();
    if (fill) ctx.fill();
    if (stroke) ctx.stroke();
  }
 
  const nodeGroup = new THREE.Group();
  scene.add(nodeGroup);
 
  const positions = [];
  const radius = 95;
 
  // Distribute words across a sphere
  for (let i = 0; i < words.length; i++) {
    const phi = Math.acos(-1 + (2 * i + 1) / words.length);
    const theta = Math.sqrt(words.length * Math.PI) * phi;
 
    const x = radius * Math.cos(theta) * Math.sin(phi);
    const y = radius * Math.sin(theta) * Math.sin(phi);
    const z = radius * Math.cos(phi);
 
    positions.push(new THREE.Vector3(x, y, z));
 
    const sprite = makeTextSprite(words[i]);
    sprite.position.set(x, y, z);
    sprite.userData.word = words[i];
    nodeGroup.add(sprite);
  }
 
  // Connect every word to every other word
  const lineMaterial = new THREE.LineBasicMaterial({
    color: 0x777777,
    transparent: true,
    opacity: 0.45
  });
 
  for (let i = 0; i < positions.length; i++) {
    for (let j = i + 1; j < positions.length; j++) {
      const geometry = new THREE.BufferGeometry().setFromPoints([
        positions[i],
        positions[j]
      ]);
      const line = new THREE.Line(geometry, lineMaterial);
      scene.add(line);
    }
  }
 
  // Small center marker
  const centerGeom = new THREE.SphereGeometry(3, 16, 16);
  const centerMat = new THREE.MeshBasicMaterial({ color: 0x222222 });
  const centerDot = new THREE.Mesh(centerGeom, centerMat);
  scene.add(centerDot);
 
  const raycaster = new THREE.Raycaster();
  const pointer = new THREE.Vector2();
 
  const info = document.createElement('div');
  info.style.position = 'absolute';
  info.style.left = '12px';
  info.style.top = '12px';
  info.style.padding = '8px 10px';
  info.style.background = 'rgba(255,255,255,0.9)';
  info.style.border = '1px solid #ccc';
  info.style.fontFamily = 'Arial, sans-serif';
  info.style.fontSize = '14px';
  info.style.color = '#111';
  info.style.zIndex = '10';
  info.innerHTML = 'Drag to rotate. Scroll to zoom. Click a word.';
  container.appendChild(info);
 
  function onPointerMove(event) {
    const rect = renderer.domElement.getBoundingClientRect();
    pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
    pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
  }
 
  function onClick() {
    raycaster.setFromCamera(pointer, camera);
    const intersects = raycaster.intersectObjects(nodeGroup.children, true);
 
    if (intersects.length > 0) {
      const obj = intersects[0].object;
      if (obj.userData && obj.userData.word) {
        info.innerHTML = 'Selected: <b>' + obj.userData.word + '</b>';
      }
    }
  }
 
  renderer.domElement.addEventListener('mousemove', onPointerMove);
  renderer.domElement.addEventListener('click', onClick);
 
  function resize() {
    const w = container.clientWidth;
    const h = container.clientHeight;
    camera.aspect = w / h;
    camera.updateProjectionMatrix();
    renderer.setSize(w, h);
  }
 
  window.addEventListener('resize', resize);
 
  function animate() {
    requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
  }
 
  animate();
})();
</script>
</html>

Latest revision as of 15:35, 4 April 2026