skip to content
reelikklemind

Yijing

Yijing Project

Last Updated:

I Ching (Yijing) Sphere



An interactive 3D visualization of the I Ching hexagrams arranged in a spherical formation.

ALWAYS REMEMBER what Lao Tzu said: "The Tao that can be spoken is not the eternal Tao."

This is only a 3D representation of a 6D structure. This is only one portion or slice of
the entity. Additionally, the I-Ching is always moving through space and time. This further complicates things.

🚀 Live Demo GIF

🔮 Features

  • Interactive 3D Sphere: Navigate through all 64 hexagrams positioned in a spherical arrangement
  • Intuitive Controls: Rotate, zoom, and interact with the sphere using mouse or touch controls
  • Hexagram Details: Click/tap on any hexagram to view its details including number, name in Chinese, pinyin, and English translation
  • Responsive Design: Optimized for both desktop and mobile devices
  • Performance Optimized: Adaptive rendering based on device capabilities

🧩 About the I Ching

The I Ching (易經), or "Book of Changes," is an ancient Chinese text dating back to the 9th century BCE. It is not just a divination text, but rather a teacher of phylosophy. It consists of 64 hexagrams, each representing a unique archetype or situation. The hexagrams are composed of six horizontal lines that can be either solid (yang) or broken (yin), read from top to bottom. This application arranges these hexagrams in a spherical pattern, with special emphasis on the pole hexagrams:

  • North Pole: Hexagram 1 (乾 Qián) - "The Creative (Initiating)"
  • South Pole: Hexagram 2 (坤 Kūn) - "The Receptive (Responding)"

The arrangement follows a logical pattern with multiple levels, thereby creating a spatial relationship between hexagrams.

📊 Hexagrams

Number Symbol Traditional Chinese Pinyin Simplified Chinese English Binary
01 qián Initiating 111111
02 kūn Responding 000000
03 zhūn Beginning 010001
04 méng Childhood 100010
05 Waiting 111010
06 sòng Contention 010111
07 shī Leading 010000
08 Grouping 000010
09 小畜 xiǎo chù 小畜 Small Accumulation 111011
10 Treading 110111
11 tài Advance 111000
12 Obstruction 000111
13 同人 tóng rén 同人 Fellowship 101111
14 大有 dà yǒu 大有 Great Possession 111101
15 qiān Humbling 000100
16 Delight 001000
17 suí Following 100110
18 Remedying 011001
19 lín Approaching 110000
20 guān Viewing 000011
21 噬嗑 shì kè 噬嗑 Eradicating 100101
22 Adorning 101001
23 Falling Away 000001
24 Returning 100000
25 無妄 wú wàng 无妄 Without Falsehood 100111
26 大畜 dà chù 大畜 Great Accumulation 111001
27 Nourishing 100001
28 大過 dà guò 大过 Great Exceeding 011110
29 kǎn Darkness 010010
30 Brightness 101101
31 xián Conjoining 001110
32 héng Perseverance 011100
33 dùn Retreating 001111
34 大壯 dà zhuàng 大壮 Great Strength 111100
35 jìn Proceeding 000101
36 明夷 míng yí 明夷 Brightness Hiding 101000
37 家人 jiā rén 家人 Dwelling People 101011
38 kuí Diversity 110101
39 jiǎn Hardship 001010
40 xiè Relief 010100
41 sǔn Decreasing 110001
42 Increasing 100011
43 guài Decisiveness 111110
44 gòu Encountering 011111
45 cuì Gathering 000110
46 shēng Growing Upward 011000
47 kùn Exhaustion 010110
48 jǐng Replenishing 011010
49 Abolishing 101110
50 dǐng Establishing 011101
51 zhèn Taking Action 100100
52 gèn Keeping Still 001001
53 jiàn Developing 001011
54 歸妹 guī mèi 归妹 Marrying 110100
55 fēng Abundance 101100
56 Traveling 001101
57 xùn Proceeding Humbly 110110
58 duì Joyful 011011
59 huàn Dispersing 010011
60 jié Restricting 110010
61 中孚 zhōng fú 中孚 Center Confirming 110011
62 小過 xiǎo guò 小过 Small Exceeding 001100
63 既濟 jì jì 既济 Already Complete 010101
64 ䷿ 未濟 wèi jì 未济 Not Yet Complete 101010

Each hexagram represents a unique situation or state, and the I Ching provides guidance on how to navigate through these circumstances. The binary representation shows the structure of each hexagram, with 1 representing yang (unbroken) lines and 0 representing yin (broken) lines, read from bottom to top.

💻 Technologies Used

  • Three.js - 3D JavaScript library
  • JavaScript (ES6+)
  • HTML5 & CSS3

🛠️ Installation & Setup

  1. Clone the repository:
    git clone <https://github.com/edisedis777/i-ching-sphere.git>
    cd i-ching-sphere
  2. Since this is a pure frontend project with ES modules, you'll need to serve it using a local server:

    Using Python:

    python -m http.server

    Or using Node.js's live-server:

    npx live-server
  3. Open your browser and navigate to http://localhost:8000 (or the port specified by your local server)

📱 Usage

  • Drag to rotate the sphere
  • Scroll/Pinch to zoom in or out
  • Click/Tap on any hexagram to view its details
  • Use the Reset View button to return to the default perspective

📂 Project Structure

i-ching-sphere/
├── index.html              # Main HTML file
├── script.js               # Main application script
├── hexagramsRendering.js   # Hexagram positioning and rendering functions
├── hexagramsData.js        # Hexagram data and positioning data
└── README.md               # This file

Code Files

Toggle to view code files

“Click to expand each file’s content. These are the core files powering the I Ching Sphere.”

  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>I Ching Sphere</title>
  <style>
    body {
      margin: 0;
      overflow: hidden;
      font-family: Arial, sans-serif;
    }
    #canvas {
      width: 100vw;
      height: 100vh;
      display: block;
    }
    #info {
      position: absolute;
      top: 10px;
      left: 10px;
      background: rgba(255, 255, 255, 0.9);
      padding: 10px;
      border-radius: 5px;
      max-width: 300px;
      font-size: 14px;
      display: none;
      z-index: 10;
    }
    #resetButton {
      position: absolute;
      bottom: 10px;
      left: 10px;
      padding: 10px 20px;
      background: #007bff;
      color: white;
      border: none;
      border-radius: 5px;
      cursor: pointer;
      z-index: 10;
    }
    #resetButton:hover {
      background: #0056b3;
    }
  </style>
</head>
<body>
  <div id="info">Click on any hexagram to see details</div>
  <div id="canvas"></div>
  <button id="resetButton">Reset View</button>
  <script type="module" src="script.js"></script>
</body>
</html>
  • script.js
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { positionHexagrams, createSphereGrid } from "./hexagramsRendering.js";

// Initialize scene, camera, and renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  65,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
const renderer = new THREE.WebGLRenderer({
  antialias: true,
  powerPreference: "high-performance", // Request high-performance GPU
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xf0f0f0);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // Cap pixel ratio for mobile performance
document.getElementById("canvas").appendChild(renderer.domElement);

// Add lighting - simplified to one light for better performance
const ambientLight = new THREE.AmbientLight(0xffffff, 2.0);
scene.add(ambientLight);

// Add orbit controls with optimized settings
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.rotateSpeed = 0.5;
controls.target.set(0, 0, 0);
camera.position.set(0, 0, 5.5);
controls.update();
controls.enablePan = false; // Disable panning for better mobile experience
controls.minDistance = 2; // Prevent zooming too close
controls.maxDistance = 10; // Limit zoom out

// Create the sphere with simplified geometry
const radius = 2;
const sphereGeometry = new THREE.SphereGeometry(radius, 24, 24); // Reduced from 32x32 to 24x24
const sphereMaterial = new THREE.MeshPhongMaterial({
  color: 0xadd8e6,
  wireframe: false,
  transparent: true,
  opacity: 0.1,
  side: THREE.DoubleSide,
});
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.set(0, 0, 0);
scene.add(sphere);

// Add grid lines to the sphere
createSphereGrid(THREE, scene, radius);

// Position hexagrams
let hexagramObjects = [];

// Wrap in a try-catch to handle any issues with hexagram loading
try {
  hexagramObjects = positionHexagrams(THREE, scene, radius);
} catch (error) {
  console.error("Error loading hexagrams:", error);
  // Display error message in the info panel
  const infoPanel = document.getElementById("info");
  infoPanel.innerHTML =
    "Error loading hexagrams. Please check console for details.";
}

// Ensure all sprites and lines are rendered on top
scene.traverse(function (object) {
  if (object instanceof THREE.Sprite || object instanceof THREE.Line) {
    object.renderOrder = 1;
  }
});

// Initialize info panel - FIXED: Show the initial instruction text
const infoPanel = document.getElementById("info");
infoPanel.style.display = "block"; // Show initially with default instruction text

// Raycaster for interactivity - optimized with cache
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
let lastInteraction = 0;

// Function to handle all interactions (clicks, touches)
function onInteract(event) {
  event.preventDefault();

  // Throttle interactions to 100ms to improve performance
  const now = Date.now();
  if (now - lastInteraction < 100) return;
  lastInteraction = now;

  const rect = renderer.domElement.getBoundingClientRect();

  // Get correct coordinates based on event type
  let clientX, clientY;
  if (event.type === "touchstart" || event.type === "touchend") {
    clientX = event.changedTouches[0].clientX;
    clientY = event.changedTouches[0].clientY;
  } else {
    clientX = event.clientX;
    clientY = event.clientY;
  }

  mouse.x = ((clientX - rect.left) / rect.width) * 2 - 1;
  mouse.y = -((clientY - rect.top) / rect.height) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);

  // Only proceed if hexagramObjects is properly loaded
  if (hexagramObjects && hexagramObjects.length > 0) {
    const intersects = raycaster.intersectObjects(
      hexagramObjects.map((o) => o.sprite),
      true
    );

    if (intersects.length > 0) {
      const hex = hexagramObjects.find(
        (o) => o.sprite === intersects[0].object
      ).data;

      // Show and update the info panel
      infoPanel.style.display = "block";
      infoPanel.innerHTML = `
        <strong>${hex.no} - ${hex.simplifiedChinese || ""} (${
        hex.pinyin || ""
      }) - ${hex.english || ""}</strong><br>
        <span style="font-family: monospace;">Lines: ${hex.lines}</span><br>
        <span>Level: ${hex.level !== undefined ? hex.level : ""}</span>
      `;

      // Highlight the clicked hexagram by scaling it up slightly
      intersects[0].object.scale.set(0.6, 0.6, 0.6);
      setTimeout(() => {
        intersects[0].object.scale.set(0.5, 0.5, 0.5);
      }, 300);
    }
  }
}

// Event Listeners for both desktop and mobile
renderer.domElement.addEventListener("click", onInteract);
renderer.domElement.addEventListener("touchend", onInteract, {
  passive: false,
});

// Override fetch to catch and handle specific CORS issues
const originalFetch = window.fetch;
window.fetch = function (url, options) {
  // Check if the URL is the problematic one
  if (
    url &&
    url.toString().includes("jreader-bucket.s3.us-east-1.amazonaws.com")
  ) {
    console.warn("Blocked fetch request to:", url);
    // Return a resolved promise with an empty response to prevent errors
    return Promise.resolve(
      new Response("", {
        status: 200,
        headers: { "Content-Type": "text/plain" },
      })
    );
  }

  // Otherwise, use the original fetch
  return originalFetch.apply(this, arguments);
};

// Animation loop with optimized frame rate
let autoRotate = true;
let lastFrame = 0;
const targetFPS = 60;
const frameInterval = 1000 / targetFPS;

function animate(timestamp) {
  requestAnimationFrame(animate);

  // Limit framerate for better performance
  if (timestamp - lastFrame < frameInterval) return;
  lastFrame = timestamp;

  if (autoRotate) {
    sphere.rotation.y += 0.001;
  }

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

// Toggle auto-rotation when interacting with controls
controls.addEventListener("start", function () {
  autoRotate = false;
});
controls.addEventListener("end", function () {
  setTimeout(() => {
    autoRotate = true;
  }, 3000);
});

// Handle window resize with debouncing
let resizeTimeout;
window.addEventListener("resize", () => {
  clearTimeout(resizeTimeout);
  resizeTimeout = setTimeout(() => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  }, 250);
});

// Add reset button with enhanced styling
const resetButton = document.getElementById("resetButton");
resetButton.addEventListener("click", () => {
  camera.position.set(0, 0, 5.5);
  controls.target.set(0, 0, 0);
  controls.update();

  // FIXED: Reset info panel to show initial instruction text rather than hiding it
  infoPanel.style.display = "block";
  infoPanel.innerHTML = "Click on any hexagram to see details";
});

// Add error handling for any other script loading issues
window.addEventListener(
  "error",
  function (event) {
    console.error("Script error caught:", event.error);
    // Only update info if it's likely related to our app
    if (
      event.filename &&
      (event.filename.includes("hexagramsData.js") ||
        event.filename.includes("hexagramsRendering.js"))
    ) {
      infoPanel.innerHTML =
        "Error loading application resources. Please check console for details.";
    }
  },
  true
);
  • hexagramsRendering.js
// hexagramsRendering.js - Optimized version for mobile
import { hexagrams } from "./hexagramsData.js";

export function positionHexagrams(THREE, scene, radius) {
  const hexagramObjects = [];
  const innerRadius = 1.0; // Radius for inner hexagrams (Levels 2 and 4)
  const centerHexagrams = [63, 64]; // Hexagrams to place near the center
  const level2Inner = [30, 57, 58]; // Level 2 inner hexagrams
  const level4Inner = [29, 51, 52]; // Level 4 inner hexagrams

  // Texture canvas size - reduce for mobile performance
  const canvasSize = window.innerWidth < 768 ? 96 : 128;

  // Create textures only once for better performance
  const createTextureCanvas = (hex) => {
    const canvas = document.createElement("canvas");
    canvas.width = canvasSize;
    canvas.height = canvasSize;
    const ctx = canvas.getContext("2d");

    // White background with border
    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, canvasSize, canvasSize);
    ctx.strokeStyle = "black";
    ctx.lineWidth = 2;
    ctx.strokeRect(0, 0, canvasSize, canvasSize);

    // Add document-like lines
    ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
    for (let i = 0; i < 8; i++) {
      ctx.fillRect(10, 30 + i * 10, canvasSize - 20, 1);
    }

    // Add hexagram number at the top
    ctx.fillStyle = "black";
    ctx.font = "bold 16px Arial";
    ctx.textAlign = "center";
    ctx.fillText(`${hex.no}`, canvasSize / 2, 20);

    // Draw the hexagram lines (solid for 1, broken for 0)
    ctx.strokeStyle = "black";
    ctx.lineWidth = 2;
    const centerX = canvasSize / 2;
    const lineWidth = canvasSize / 3;

    for (let i = 0; i < 6; i++) {
      const y = 40 + i * 10; // Stack lines vertically
      ctx.beginPath();
      if (hex.lines[i] === "1") {
        // Solid line (yang)
        ctx.moveTo(centerX - lineWidth / 2, y);
        ctx.lineTo(centerX + lineWidth / 2, y);
      } else {
        // Broken line (yin)
        ctx.moveTo(centerX - lineWidth / 2, y);
        ctx.lineTo(centerX - lineWidth / 6, y);
        ctx.moveTo(centerX + lineWidth / 6, y);
        ctx.lineTo(centerX + lineWidth / 2, y);
      }
      ctx.stroke();
    }

    // Highlight the edges of the card to make it more visible
    ctx.strokeStyle = "rgba(0, 0, 0, 0.8)";
    ctx.lineWidth = 2;
    ctx.strokeRect(2, 2, canvasSize - 4, canvasSize - 4);

    return canvas;
  };

  // Determine sprite scale based on device size
  const spriteScale = window.innerWidth < 768 ? 0.4 : 0.5;

  hexagrams.forEach((hex) => {
    let x, y, z;

    if (centerHexagrams.includes(hex.no)) {
      // Place near the center, offset along the x-axis
      const offset = hex.no === 63 ? -0.1 : 0.1; // Offset for hex 63 and 64
      x = offset;
      y = 0;
      z = 0;
    } else if (level2Inner.includes(hex.no) || level4Inner.includes(hex.no)) {
      // Place at inner radius
      x = innerRadius * Math.sin(hex.theta) * Math.cos(hex.phi);
      y = innerRadius * Math.cos(hex.theta);
      z = innerRadius * Math.sin(hex.theta) * Math.sin(hex.phi);
    } else {
      // Place on the sphere's surface
      x = radius * Math.sin(hex.theta) * Math.cos(hex.phi);
      y = radius * Math.cos(hex.theta);
      z = radius * Math.sin(hex.theta) * Math.sin(hex.phi);
    }

    // Create texture canvas
    const canvas = createTextureCanvas(hex);
    const texture = new THREE.CanvasTexture(canvas);
    texture.needsUpdate = true;

    // Create material with optimized parameters for mobile
    const spriteMaterial = new THREE.SpriteMaterial({
      map: texture,
      sizeAttenuation: true,
      depthTest: false,
      depthWrite: false,
      transparent: true,
      opacity: 0.95,
    });

    const sprite = new THREE.Sprite(spriteMaterial);
    sprite.position.set(x, y, z);
    sprite.scale.set(spriteScale, spriteScale, spriteScale);
    sprite.userData = { hexagramNo: hex.no }; // Store reference for raycasting

    // Special highlighting for the pole hexagrams
    if (hex.no === 1) {
      // Red highlighting for North pole (hexagram 1)
      addHighlight(
        THREE,
        scene,
        x,
        y,
        z,
        "rgba(255, 0, 0, 0.3)",
        "red",
        "North",
        y + 0.4,
        spriteScale
      );
    } else if (hex.no === 2) {
      // Blue highlighting for South pole (hexagram 2)
      addHighlight(
        THREE,
        scene,
        x,
        y,
        z,
        "rgba(0, 0, 255, 0.3)",
        "blue",
        "South",
        y - 0.4,
        spriteScale
      );
    }

    scene.add(sprite);
    hexagramObjects.push({ sprite, data: hex });
  });

  return hexagramObjects;
}

// Helper function to add highlights and labels to pole hexagrams
function addHighlight(
  THREE,
  scene,
  x,
  y,
  z,
  highlightColor,
  labelColor,
  labelText,
  labelY,
  scale
) {
  // Create highlight sprite
  const highlightCanvas = document.createElement("canvas");
  highlightCanvas.width = 128;
  highlightCanvas.height = 128;
  const highlightCtx = highlightCanvas.getContext("2d");
  highlightCtx.fillStyle = highlightColor;
  highlightCtx.fillRect(0, 0, 128, 128);

  const highlightTexture = new THREE.CanvasTexture(highlightCanvas);
  const highlightMaterial = new THREE.SpriteMaterial({
    map: highlightTexture,
    transparent: true,
    depthTest: false,
    depthWrite: false,
    opacity: 0.7,
  });

  const highlight = new THREE.Sprite(highlightMaterial);
  highlight.position.set(x, y, z);
  highlight.scale.set(scale * 1.1, scale * 1.1, scale * 1.1);
  scene.add(highlight);

  // Add label
  const labelCanvas = document.createElement("canvas");
  labelCanvas.width = 200;
  labelCanvas.height = 50;
  const labelCtx = labelCanvas.getContext("2d");
  labelCtx.fillStyle = labelColor;
  labelCtx.font = "bold 24px Arial";
  labelCtx.textAlign = "center";
  labelCtx.fillText(labelText, 100, 30);

  const labelTexture = new THREE.CanvasTexture(labelCanvas);
  const labelMaterial = new THREE.SpriteMaterial({
    map: labelTexture,
    transparent: true,
    depthTest: false,
    depthWrite: false,
  });

  const label = new THREE.Sprite(labelMaterial);
  label.position.set(x, labelY, z);
  label.scale.set(0.8, 0.2, 0.2);
  scene.add(label);
}

// Add a function to create grid lines on the sphere - optimized for mobile
export function createSphereGrid(THREE, scene, radius) {
  // Determine grid complexity based on device
  const isMobile = window.innerWidth < 768;
  const material = new THREE.LineBasicMaterial({
    color: 0x0000ff,
    transparent: true,
    opacity: isMobile ? 0.2 : 0.3,
    depthTest: false,
    depthWrite: false,
  });

  // Reduce complexity on mobile
  const longitudeCount = isMobile ? 6 : 8;
  const latitudeCount = isMobile ? 4 : 5;
  const segmentCount = isMobile ? 16 : 24;

  // Create longitude lines (vertical)
  for (let i = 0; i < longitudeCount; i++) {
    const phi = (i / longitudeCount) * Math.PI * 2;
    const points = [];

    for (let j = 0; j <= segmentCount; j++) {
      const theta = (j / segmentCount) * Math.PI;
      const x = radius * Math.sin(theta) * Math.cos(phi);
      const y = radius * Math.cos(theta);
      const z = radius * Math.sin(theta) * Math.sin(phi);

      points.push(new THREE.Vector3(x, y, z));
    }

    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    const line = new THREE.Line(geometry, material);
    scene.add(line);
  }

  // Create fewer latitude lines (horizontal) on mobile for better performance
  for (let i = 1; i < latitudeCount; i++) {
    const theta = (i / latitudeCount) * Math.PI;
    const points = [];

    for (let j = 0; j <= segmentCount; j++) {
      const phi = (j / segmentCount) * Math.PI * 2;
      const x = radius * Math.sin(theta) * Math.cos(phi);
      const y = radius * Math.cos(theta);
      const z = radius * Math.sin(theta) * Math.sin(phi);

      points.push(new THREE.Vector3(x, y, z));
    }

    const geometry = new THREE.BufferGeometry().setFromPoints(points);
    const line = new THREE.Line(geometry, material);
    scene.add(line);
  }
}
  • hexagramsData.js
// hexagramsData.js
export const hexagrams = [
  // Level 0 (θ = 0, 1 hexagram)
  {
    no: 1,
    number: "01",
    symbol: "䷀",
    traditionalChinese: "乾",
    pinyin: "qián",
    simplifiedChinese: "乾",
    english: "Initiating",
    lines: "111111",
    level: 0,
    theta: 0,
    phi: 0,
  },

  // Level 1 (θ = π/6, 6 hexagrams at 60°)
  {
    no: 43,
    number: "43",
    symbol: "䷪",
    traditionalChinese: "夬",
    pinyin: "guài",
    simplifiedChinese: "夬",
    english: "Eliminating",
    lines: "111110",
    level: 1,
    theta: Math.PI / 6,
    phi: 0,
  },
  {
    no: 44,
    number: "44",
    symbol: "䷫",
    traditionalChinese: "姤",
    pinyin: "gòu",
    simplifiedChinese: "姤",
    english: "Encountering",
    lines: "011111",
    level: 1,
    theta: Math.PI / 6,
    phi: Math.PI / 3,
  },
  {
    no: 13,
    number: "13",
    symbol: "䷌",
    traditionalChinese: "同人",
    pinyin: "tóng rén",
    simplifiedChinese: "同人",
    english: "Seeking Harmony",
    lines: "111101",
    level: 1,
    theta: Math.PI / 6,
    phi: (2 * Math.PI) / 3,
  },
  {
    no: 10,
    number: "10",
    symbol: "䷉",
    traditionalChinese: "履",
    pinyin: "lǚ",
    simplifiedChinese: "履",
    english: "Fulfillment",
    lines: "111011",
    level: 1,
    theta: Math.PI / 6,
    phi: Math.PI,
  },
  {
    no: 9,
    number: "09",
    symbol: "䷈",
    traditionalChinese: "小畜",
    pinyin: "xiǎo chù",
    simplifiedChinese: "小畜",
    english: "Little Accumulation",
    lines: "110111",
    level: 1,
    theta: Math.PI / 6,
    phi: (4 * Math.PI) / 3,
  },
  {
    no: 14,
    number: "14",
    symbol: "䷍",
    traditionalChinese: "大有",
    pinyin: "dà yǒu",
    simplifiedChinese: "大有",
    english: "Great Harvest",
    lines: "101111",
    level: 1,
    theta: Math.PI / 6,
    phi: (5 * Math.PI) / 3,
  },

  // Level 2 (θ = π/3, 12 outer at 30° + 3 inner)
  {
    no: 5,
    number: "05",
    symbol: "䷄",
    traditionalChinese: "需",
    pinyin: "xū",
    simplifiedChinese: "需",
    english: "Needing",
    lines: "010111",
    level: 2,
    theta: Math.PI / 3,
    phi: 0,
  },
  {
    no: 34,
    number: "34",
    symbol: "䷡",
    traditionalChinese: "大壯",
    pinyin: "dà zhuàng",
    simplifiedChinese: "大壮",
    english: "Great Strength",
    lines: "001111",
    level: 2,
    theta: Math.PI / 3,
    phi: Math.PI / 6,
  },
  {
    no: 50,
    number: "50",
    symbol: "䷱",
    traditionalChinese: "鼎",
    pinyin: "dǐng",
    simplifiedChinese: "鼎",
    english: "Establishing The New",
    lines: "101110",
    level: 2,
    theta: Math.PI / 3,
    phi: Math.PI / 3,
  },
  {
    no: 28,
    number: "28",
    symbol: "䷛",
    traditionalChinese: "大過",
    pinyin: "dà guò",
    simplifiedChinese: "大过",
    english: "Great Exceeding",
    lines: "011110",
    level: 2,
    theta: Math.PI / 3,
    phi: Math.PI / 2,
  },
  {
    no: 49,
    number: "49",
    symbol: "䷰",
    traditionalChinese: "革",
    pinyin: "gé",
    simplifiedChinese: "革",
    english: "Abolishing The Old",
    lines: "011101",
    level: 2,
    theta: Math.PI / 3,
    phi: (2 * Math.PI) / 3,
  },
  {
    no: 33,
    number: "33",
    symbol: "䷠",
    traditionalChinese: "遯",
    pinyin: "dùn",
    simplifiedChinese: "遯",
    english: "Retreat",
    lines: "111100",
    level: 2,
    theta: Math.PI / 3,
    phi: (5 * Math.PI) / 6,
  },
  {
    no: 6,
    number: "06",
    symbol: "䷅",
    traditionalChinese: "訟",
    pinyin: "sòng",
    simplifiedChinese: "讼",
    english: "Contention",
    lines: "111010",
    level: 2,
    theta: Math.PI / 3,
    phi: Math.PI,
  },
  {
    no: 25,
    number: "25",
    symbol: "䷘",
    traditionalChinese: "無妄",
    pinyin: "wú wàng",
    simplifiedChinese: "无妄",
    english: "Without Falsehood",
    lines: "111001",
    level: 2,
    theta: Math.PI / 3,
    phi: (7 * Math.PI) / 6,
  },
  {
    no: 37,
    number: "37",
    symbol: "䷤",
    traditionalChinese: "家人",
    pinyin: "jiā rén",
    simplifiedChinese: "家人",
    english: "Household",
    lines: "110101",
    level: 2,
    theta: Math.PI / 3,
    phi: (4 * Math.PI) / 3,
  },
  {
    no: 61,
    number: "61",
    symbol: "䷼",
    traditionalChinese: "中孚",
    pinyin: "zhōng fú",
    simplifiedChinese: "中孚",
    english: "Innermost Sincerity",
    lines: "110011",
    level: 2,
    theta: Math.PI / 3,
    phi: (3 * Math.PI) / 2,
  },
  {
    no: 38,
    number: "38",
    symbol: "䷥",
    traditionalChinese: "睽",
    pinyin: "kuí",
    simplifiedChinese: "睽",
    english: "Diversity",
    lines: "101011",
    level: 2,
    theta: Math.PI / 3,
    phi: (5 * Math.PI) / 3,
  },
  {
    no: 26,
    number: "26",
    symbol: "䷙",
    traditionalChinese: "大畜",
    pinyin: "dà chù",
    simplifiedChinese: "大畜",
    english: "Great Accumulation",
    lines: "100111",
    level: 2,
    theta: Math.PI / 3,
    phi: (11 * Math.PI) / 6,
  },
  // Inner circle (centered on main axis)
  {
    no: 30,
    number: "30",
    symbol: "䷝",
    traditionalChinese: "離",
    pinyin: "lí",
    simplifiedChinese: "离",
    english: "Brightness",
    lines: "101101",
    level: 2,
    theta: Math.PI / 3,
    phi: 0,
  },
  {
    no: 57,
    number: "57",
    symbol: "䷸",
    traditionalChinese: "巽",
    pinyin: "xùn",
    simplifiedChinese: "巽",
    english: "Proceeding Humbly",
    lines: "110110",
    level: 2,
    theta: Math.PI / 3,
    phi: Math.PI / 2,
  },
  {
    no: 58,
    number: "58",
    symbol: "䷹",
    traditionalChinese: "兌",
    pinyin: "duì",
    simplifiedChinese: "兑",
    english: "Joyful",
    lines: "011011",
    level: 2,
    theta: Math.PI / 3,
    phi: Math.PI,
  },

  // Level 3 (θ = π/2, 6 groups of 3 + 2 inner)
  {
    no: 54,
    number: "54",
    symbol: "䷵",
    traditionalChinese: "歸妹",
    pinyin: "guī mèi",
    simplifiedChinese: "归妹",
    english: "Marrying Maiden",
    lines: "001011",
    level: 3,
    theta: Math.PI / 2,
    phi: 0,
  },
  {
    no: 11,
    number: "11",
    symbol: "䷊",
    traditionalChinese: "泰",
    pinyin: "tài",
    simplifiedChinese: "泰",
    english: "Advance",
    lines: "000111",
    level: 3,
    theta: Math.PI / 2,
    phi: Math.PI / 12,
  },
  {
    no: 18,
    number: "18",
    symbol: "䷑",
    traditionalChinese: "蠱",
    pinyin: "gǔ",
    simplifiedChinese: "蛊",
    english: "Remedying",
    lines: "100110",
    level: 3,
    theta: Math.PI / 2,
    phi: Math.PI / 6,
  },
  {
    no: 48,
    number: "48",
    symbol: "䷯",
    traditionalChinese: "井",
    pinyin: "jǐng",
    simplifiedChinese: "井",
    english: "Replenishing",
    lines: "010110",
    level: 3,
    theta: Math.PI / 2,
    phi: Math.PI / 3,
  },
  {
    no: 32,
    number: "32",
    symbol: "䷟",
    traditionalChinese: "恆",
    pinyin: "héng",
    simplifiedChinese: "恒",
    english: "Long Lasting",
    lines: "001110",
    level: 3,
    theta: Math.PI / 2,
    phi: (5 * Math.PI) / 12,
  },
  {
    no: 55,
    number: "55",
    symbol: "䷶",
    traditionalChinese: "豐",
    pinyin: "fēng",
    simplifiedChinese: "丰",
    english: "Abundance",
    lines: "001101",
    level: 3,
    theta: Math.PI / 2,
    phi: Math.PI / 2,
  },
  {
    no: 47,
    number: "47",
    symbol: "䷮",
    traditionalChinese: "困",
    pinyin: "kùn",
    simplifiedChinese: "困",
    english: "Exhausting",
    lines: "011010",
    level: 3,
    theta: Math.PI / 2,
    phi: (2 * Math.PI) / 3,
  },
  {
    no: 31,
    number: "31",
    symbol: "䷞",
    traditionalChinese: "咸",
    pinyin: "xián",
    simplifiedChinese: "咸",
    english: "Mutual Influence",
    lines: "011100",
    level: 3,
    theta: Math.PI / 2,
    phi: (7 * Math.PI) / 12,
  },
  {
    no: 56,
    number: "56",
    symbol: "䷷",
    traditionalChinese: "旅",
    pinyin: "lǚ",
    simplifiedChinese: "旅",
    english: "Travelling",
    lines: "101100",
    level: 3,
    theta: Math.PI / 2,
    phi: (3 * Math.PI) / 4,
  },
  {
    no: 53,
    number: "53",
    symbol: "䷴",
    traditionalChinese: "漸",
    pinyin: "jiàn",
    simplifiedChinese: "渐",
    english: "Developing Gradually",
    lines: "110100",
    level: 3,
    theta: Math.PI / 2,
    phi: Math.PI,
  },
  {
    no: 12,
    number: "12",
    symbol: "䷋",
    traditionalChinese: "否",
    pinyin: "pǐ",
    simplifiedChinese: "否",
    english: "Hindrance",
    lines: "111000",
    level: 3,
    theta: Math.PI / 2,
    phi: (11 * Math.PI) / 12,
  },
  {
    no: 17,
    number: "17",
    symbol: "䷐",
    traditionalChinese: "隨",
    pinyin: "suí",
    simplifiedChinese: "随",
    english: "Following",
    lines: "011001",
    level: 3,
    theta: Math.PI / 2,
    phi: (7 * Math.PI) / 6,
  },
  {
    no: 21,
    number: "21",
    symbol: "䷔",
    traditionalChinese: "噬嗑",
    pinyin: "shì kè",
    simplifiedChinese: "噬嗑",
    english: "Eradicating",
    lines: "101001",
    level: 3,
    theta: Math.PI / 2,
    phi: (4 * Math.PI) / 3,
  },
  {
    no: 42,
    number: "42",
    symbol: "䷩",
    traditionalChinese: "益",
    pinyin: "yì",
    simplifiedChinese: "益",
    english: "Increasing",
    lines: "110001",
    level: 3,
    theta: Math.PI / 2,
    phi: (17 * Math.PI) / 12,
  },
  {
    no: 59,
    number: "59",
    symbol: "䷺",
    traditionalChinese: "渙",
    pinyin: "huàn",
    simplifiedChinese: "涣",
    english: "Dispersing",
    lines: "110010",
    level: 3,
    theta: Math.PI / 2,
    phi: (3 * Math.PI) / 2,
  },
  {
    no: 22,
    number: "22",
    symbol: "䷕",
    traditionalChinese: "賁",
    pinyin: "bì",
    simplifiedChinese: "贲",
    english: "Adorning",
    lines: "100101",
    level: 3,
    theta: Math.PI / 2,
    phi: (5 * Math.PI) / 3,
  },
  {
    no: 41,
    number: "41",
    symbol: "䷨",
    traditionalChinese: "損",
    pinyin: "sǔn",
    simplifiedChinese: "损",
    english: "Decreasing",
    lines: "100011",
    level: 3,
    theta: Math.PI / 2,
    phi: (19 * Math.PI) / 12,
  },
  {
    no: 60,
    number: "60",
    symbol: "䷻",
    traditionalChinese: "節",
    pinyin: "jié",
    simplifiedChinese: "节",
    english: "Restricting",
    lines: "010011",
    level: 3,
    theta: Math.PI / 2,
    phi: (11 * Math.PI) / 6,
  },
  // Inner circle
  {
    no: 63,
    number: "63",
    symbol: "䷾",
    traditionalChinese: "既濟",
    pinyin: "jì jì",
    simplifiedChinese: "既济",
    english: "Already Fulfilled",
    lines: "010101",
    level: 3,
    theta: Math.PI / 2,
    phi: 0,
  },
  {
    no: 64,
    number: "64",
    symbol: "䷿",
    traditionalChinese: "未濟",
    pinyin: "wèi jì",
    simplifiedChinese: "未济",
    english: "Not Yet Fulfilled",
    lines: "101010",
    level: 3,
    theta: Math.PI / 2,
    phi: Math.PI,
  },

  // Level 4 (θ = 2π/3, 12 outer at 30° + 3 inner)
  {
    no: 36,
    number: "36",
    symbol: "䷣",
    traditionalChinese: "明夷",
    pinyin: "míng yí",
    simplifiedChinese: "明夷",
    english: "Brilliance Injured",
    lines: "000101",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: 0,
  },
  {
    no: 46,
    number: "46",
    symbol: "䷭",
    traditionalChinese: "升",
    pinyin: "shēng",
    simplifiedChinese: "升",
    english: "Growing Upward",
    lines: "000110",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: Math.PI / 6,
  },
  {
    no: 40,
    number: "40",
    symbol: "䷧",
    traditionalChinese: "解",
    pinyin: "xiè",
    simplifiedChinese: "解",
    english: "Relief",
    lines: "001010",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: Math.PI / 3,
  },
  {
    no: 62,
    number: "62",
    symbol: "䷽",
    traditionalChinese: "小過",
    pinyin: "xiǎo guò",
    simplifiedChinese: "小过",
    english: "Little Exceeding",
    lines: "001100",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: Math.PI / 2,
  },
  {
    no: 39,
    number: "39",
    symbol: "䷦",
    traditionalChinese: "蹇",
    pinyin: "jiǎn",
    simplifiedChinese: "蹇",
    english: "Hardship",
    lines: "010100",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: (2 * Math.PI) / 3,
  },
  {
    no: 45,
    number: "45",
    symbol: "䷬",
    traditionalChinese: "萃",
    pinyin: "cuì",
    simplifiedChinese: "萃",
    english: "Bringing Together",
    lines: "011000",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: (5 * Math.PI) / 6,
  },
  {
    no: 35,
    number: "35",
    symbol: "䷢",
    traditionalChinese: "晉",
    pinyin: "jìn",
    simplifiedChinese: "晋",
    english: "Proceeding Forward",
    lines: "101000",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: Math.PI,
  },
  {
    no: 20,
    number: "20",
    symbol: "䷓",
    traditionalChinese: "觀",
    pinyin: "guān",
    simplifiedChinese: "观",
    english: "Watching",
    lines: "110000",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: (7 * Math.PI) / 6,
  },
  {
    no: 3,
    number: "03",
    symbol: "䷂",
    traditionalChinese: "屯",
    pinyin: "zhūn",
    simplifiedChinese: "屯",
    english: "Beginning",
    lines: "010001",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: (4 * Math.PI) / 3,
  },
  {
    no: 27,
    number: "27",
    symbol: "䷚",
    traditionalChinese: "頤",
    pinyin: "yí",
    simplifiedChinese: "颐",
    english: "Nourishing",
    lines: "100001",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: (3 * Math.PI) / 2,
  },
  {
    no: 4,
    number: "04",
    symbol: "䷃",
    traditionalChinese: "蒙",
    pinyin: "méng",
    simplifiedChinese: "蒙",
    english: "Childhood",
    lines: "100010",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: (5 * Math.PI) / 3,
  },
  {
    no: 19,
    number: "19",
    symbol: "䷒",
    traditionalChinese: "臨",
    pinyin: "lín",
    simplifiedChinese: "临",
    english: "Approaching",
    lines: "000011",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: (11 * Math.PI) / 6,
  },
  // Inner circle
  {
    no: 29,
    number: "29",
    symbol: "䷜",
    traditionalChinese: "坎",
    pinyin: "kǎn",
    simplifiedChinese: "坎",
    english: "Darkness",
    lines: "010010",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: 0,
  },
  {
    no: 51,
    number: "51",
    symbol: "䷲",
    traditionalChinese: "震",
    pinyin: "zhèn",
    simplifiedChinese: "震",
    english: "Taking Action",
    lines: "001001",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: Math.PI / 2,
  },
  {
    no: 52,
    number: "52",
    symbol: "䷳",
    traditionalChinese: "艮",
    pinyin: "gèn",
    simplifiedChinese: "艮",
    english: "Keeping Still",
    lines: "100100",
    level: 4,
    theta: (2 * Math.PI) / 3,
    phi: Math.PI,
  },

  // Level 5 (θ = 5π/6, 6 hexagrams at 60°)
  {
    no: 7,
    number: "07",
    symbol: "䷆",
    traditionalChinese: "師",
    pinyin: "shī",
    simplifiedChinese: "师",
    english: "Multitude",
    lines: "000010",
    level: 5,
    theta: (5 * Math.PI) / 6,
    phi: 0,
  },
  {
    no: 15,
    number: "15",
    symbol: "䷎",
    traditionalChinese: "謙",
    pinyin: "qiān",
    simplifiedChinese: "谦",
    english: "Humbleness",
    lines: "000100",
    level: 5,
    theta: (5 * Math.PI) / 6,
    phi: Math.PI / 3,
  },
  {
    no: 16,
    number: "16",
    symbol: "䷏",
    traditionalChinese: "豫",
    pinyin: "yù",
    simplifiedChinese: "豫",
    english: "Delight",
    lines: "001000",
    level: 5,
    theta: (5 * Math.PI) / 6,
    phi: (2 * Math.PI) / 3,
  },
  {
    no: 8,
    number: "08",
    symbol: "䷇",
    traditionalChinese: "比",
    pinyin: "bǐ",
    simplifiedChinese: "比",
    english: "Union",
    lines: "010000",
    level: 5,
    theta: (5 * Math.PI) / 6,
    phi: Math.PI,
  },
  {
    no: 23,
    number: "23",
    symbol: "䷖",
    traditionalChinese: "剝",
    pinyin: "bō",
    simplifiedChinese: "剥",
    english: "Falling Away",
    lines: "100000",
    level: 5,
    theta: (5 * Math.PI) / 6,
    phi: (4 * Math.PI) / 3,
  },
  {
    no: 24,
    number: "24",
    symbol: "䷗",
    traditionalChinese: "復",
    pinyin: "fù",
    simplifiedChinese: "复",
    english: "Turning Back",
    lines: "000001",
    level: 5,
    theta: (5 * Math.PI) / 6,
    phi: (5 * Math.PI) / 3,
  },

  // Level 6 (θ = π, 1 hexagram)
  {
    no: 2,
    number: "02",
    symbol: "䷁",
    traditionalChinese: "坤",
    pinyin: "kūn",
    simplifiedChinese: "坤",
    english: "Responding",
    lines: "000000",
    level: 6,
    theta: Math.PI,
    phi: 0,
  },
];

export const paths = [
  { from: 2, to: 24 }, // Receptive (000000) to Return (000001)
  //{ from: 2, to: 7 }, // Receptive (000000) to The Army (000010)
  //{ from: 1, to: 14 }, // The Creative (111111) to Possession in Great Measure (111101)
  { from: 1, to: 43 }, // The Creative (111111) to Breakthrough (111110)
  //{ from: 12, to: 45 }, // Standstill (000111) to Gathering Together (000110)
  //{ from: 50, to: 56 }, // The Cauldron (101011) to The Wanderer (101100)
];

🔄 Performance Considerations

The application includes several optimizations for mobile devices:

  • Adaptive rendering quality based on device capabilities
  • Reduced geometry complexity on mobile devices
  • Optimized texture sizes for better performance
  • Frame rate limiting for consistent experience across devices

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

🙏 Credits

📜 License

Distributed under the GNU Affero General Public License v3.0 License. See LICENSE for more information.