Test: Difference between revisions

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


Thank you if you have subscribed recently, interest is growing. If you missed the last announcement - we have the full Summer of Extreme Design-Build starting in September, We just announced our first ever 6 month-long immersion Apprenticeship - which allows you to work with OSE full time after you finsih. And, we are ulready taking preorders on the Seed Eco-Home 2 - if you want a turnkey build of a 1000 square foot home. We are still buildig right now, we will build another model for a first client, and we will do another build after that so that we have ample and detailed video footage that allows us to make the most comprehensive sets of building instructions to date. We have 5 cameras and time lapses rolling, and our clear goal is instructions that are so easy for anyone to follow - that we literally enable thousands of such builds all around the world in the next year. That would be success. So take a look at the above links, 
<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>


<script>
(function () {
  const container = document.getElementById('ose-3d-mindmap');
  if (!container) return;


  const words = [
    "collaborative",
    "design",
    "for",
    "a",
    "transparent",
    "and",
    "inclusive",
    "economy",
    "of",
    "abundance"
  ];


https://wiki.opensourceecology.org/images/8/8a/Programs2021.jpg
  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