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.
Github Project Link
🚀 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 | ䷄ | 需 | xū | 需 | Waiting | 111010 |
06 | ䷅ | 訟 | sòng | 讼 | Contention | 010111 |
07 | ䷆ | 師 | shī | 师 | Leading | 010000 |
08 | ䷇ | 比 | bǐ | 比 | Grouping | 000010 |
09 | ䷈ | 小畜 | xiǎo chù | 小畜 | Small Accumulation | 111011 |
10 | ䷉ | 履 | lǚ | 履 | Treading | 110111 |
11 | ䷊ | 泰 | tài | 泰 | Advance | 111000 |
12 | ䷋ | 否 | pǐ | 否 | Obstruction | 000111 |
13 | ䷌ | 同人 | tóng rén | 同人 | Fellowship | 101111 |
14 | ䷍ | 大有 | dà yǒu | 大有 | Great Possession | 111101 |
15 | ䷎ | 謙 | qiān | 谦 | Humbling | 000100 |
16 | ䷏ | 豫 | yù | 豫 | Delight | 001000 |
17 | ䷐ | 隨 | suí | 随 | Following | 100110 |
18 | ䷑ | 蠱 | gǔ | 蛊 | Remedying | 011001 |
19 | ䷒ | 臨 | lín | 临 | Approaching | 110000 |
20 | ䷓ | 觀 | guān | 观 | Viewing | 000011 |
21 | ䷔ | 噬嗑 | shì kè | 噬嗑 | Eradicating | 100101 |
22 | ䷕ | 賁 | bì | 贲 | Adorning | 101001 |
23 | ䷖ | 剝 | bō | 剥 | Falling Away | 000001 |
24 | ䷗ | 復 | fù | 复 | Returning | 100000 |
25 | ䷘ | 無妄 | wú wàng | 无妄 | Without Falsehood | 100111 |
26 | ䷙ | 大畜 | dà chù | 大畜 | Great Accumulation | 111001 |
27 | ䷚ | 頤 | yí | 颐 | Nourishing | 100001 |
28 | ䷛ | 大過 | dà guò | 大过 | Great Exceeding | 011110 |
29 | ䷜ | 坎 | kǎn | 坎 | Darkness | 010010 |
30 | ䷝ | 離 | lí | 离 | 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 | ䷩ | 益 | yì | 益 | 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 | ䷰ | 革 | gé | 革 | 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 | ䷷ | 旅 | lǚ | 旅 | 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
- Clone the repository:
git clone <https://github.com/edisedis777/i-ching-sphere.git> cd i-ching-sphere
- 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
- 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.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
🙏 Credits
- This project was inspired by the work of Drasny József on the I Ching Globe. You can read more about it here: I Ching Globe PDF
- I Ching on Wikibooks for the hexagram data
📜 License
Distributed under the GNU Affero General Public License v3.0 License. See LICENSE
for more information.