/** * ============================================================================ * 意识三维空间可视化模块 (Consciousness 3D Space Visualization) * ============================================================================ * * 基于 Three.js r150+ 的 AI 意识系统 3D 可视化引擎 * 使用 Web Components (Custom Elements + Shadow DOM) 封装 * * 核心可视化元素: * 1. 记忆星云 (Memory Nebula) - 记忆以星辰形式存在于星云中 * 2. 知识图谱 (Knowledge Graph) - 实体与关系的力导向三维布局 * 3. 目标晶体 (Goal Crystals) - 以多面体晶体展示目标层级 * 4. 技能光环 (Skill Halos) - 圆环形态展示技能熟练度 * 5. 情绪粒子 (Emotion Particles) - 粒子系统展示情绪状态 * 6. 反思之镜 (Reflection Mirror) - 半透明镜面带水波效果 * 7. 社交网络 (Social Network) - 用户节点与关系连线 * * @author Bailongma AI System * @version 2.0.0 * @license MIT * ============================================================================ */ /* ========================================================================= * 全局常量与工具函数 * ========================================================================= */ /** 情绪颜色映射 */ const EMOTION_COLORS = { joy: 0xFFD700, // 金色 - 喜悦 sadness: 0x4169E1, // 蓝色 - 悲伤 anger: 0xFF2400, // 红色 - 愤怒 curiosity: 0x00E676, // 绿色 - 好奇 fear: 0x9C27B0, // 紫色 - 恐惧 surprise: 0xFF6F00, // 橙色 - 惊讶 disgust: 0x4E342E, // 棕色 - 厌恶 trust: 0x2196F3, // 浅蓝 - 信任 }; /** 目标状态颜色映射 */ const GOAL_STATE_COLORS = { completed: 0x00E676, // 绿色 - 完成 active: 0xFFD700, // 黄色 - 进行中 paused: 0x78909C, // 灰色 - 暂停 abandoned: 0xF44336, // 红色 - 放弃 }; /** 实体类型颜色映射 */ const ENTITY_TYPE_COLORS = { person: 0x42A5F5, // 蓝色 concept: 0xAB47BC, // 紫色 location: 0x66BB6A, // 绿色 event: 0xFFA726, // 橙色 skill: 0x26C6DA, // 青色 emotion: 0xEF5350, // 粉红 object: 0xFFEE58, // 黄色 default: 0xBDBDBD, // 灰色 }; /** 技能类型颜色映射 */ const SKILL_TYPE_COLORS = { technical: 0x00BCD4, // 青色 creative: 0xE91E63, // 粉红 social: 0x4CAF50, // 绿色 analytical: 0x2196F3, // 蓝色 physical: 0xFF9800, // 橙色 default: 0xBDBDBD, // 灰色 }; /** 视图模式枚举 */ const VIEW_MODES = { ALL: 'all', MEMORY: 'memory', KNOWLEDGE: 'knowledge', GOALS: 'goals', SKILLS: 'skills', EMOTIONS: 'emotions', SOCIAL: 'social', PANORAMIC: 'panoramic', }; /** 缓动函数 */ function easeInOutCubic(t) { return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; } /** 生成随机范围数 */ function randomRange(min, max) { return Math.random() * (max - min) + min; } /** 向量归一化到指定范围 */ function normalizeToRange(value, min, max, newMin, newMax) { return ((value - min) / (max - min)) * (newMax - newMin) + newMin; } /* ========================================================================= * 自定义着色器 (Custom Shaders) * ========================================================================= */ /** 星辰着色器 - 带呼吸闪烁效果 */ const STAR_VERTEX_SHADER = ` attribute float size; attribute float importance; attribute vec3 customColor; varying vec3 vColor; varying float vImportance; uniform float time; uniform float globalBrightness; void main() { vColor = customColor; vImportance = importance; vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); // 呼吸闪烁:重要性越高的星星闪烁越稳定 float breathe = 1.0 + 0.3 * (1.0 - importance) * sin(time * 2.0 + position.x * 10.0); // 大小基于重要性和到相机距离 gl_PointSize = size * breathe * globalBrightness * (300.0 / -mvPosition.z); gl_PointSize = clamp(gl_PointSize, 1.0, 100.0); gl_Position = projectionMatrix * mvPosition; } `; const STAR_FRAGMENT_SHADER = ` varying vec3 vColor; varying float vImportance; uniform float time; void main() { // 创建柔和的圆形星点 vec2 center = gl_PointCoord - vec2(0.5); float dist = length(center); // 边缘衰减 if (dist > 0.5) discard; // 核心高亮 + 外围辉光 float core = exp(-dist * dist * 30.0); float glow = exp(-dist * dist * 8.0); float alpha = mix(glow * 0.6, core, vImportance * 0.8); // 添加微妙的色彩脉动 vec3 color = vColor + 0.1 * sin(time * 1.5 + vImportance * 6.28) * vec3(0.2, 0.1, 0.0); gl_FragColor = vec4(color, alpha); } `; /** 粒子系统着色器 - 情绪粒子 */ const PARTICLE_VERTEX_SHADER = ` attribute float size; attribute float alpha; attribute vec3 customColor; varying vec3 vColor; varying float vAlpha; void main() { vColor = customColor; vAlpha = alpha; vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); gl_PointSize = size * (250.0 / -mvPosition.z); gl_PointSize = clamp(gl_PointSize, 1.0, 80.0); gl_Position = projectionMatrix * mvPosition; } `; const PARTICLE_FRAGMENT_SHADER = ` varying vec3 vColor; varying float vAlpha; void main() { float dist = length(gl_PointCoord - vec2(0.5)); if (dist > 0.5) discard; float softEdge = 1.0 - smoothstep(0.2, 0.5, dist); gl_FragColor = vec4(vColor, vAlpha * softEdge); } `; /** 水波纹效果着色器 */ const WATER_VERTEX_SHADER = ` varying vec2 vUv; uniform float time; void main() { vUv = uv; vec3 pos = position; // 水波纹位移 float wave1 = sin(pos.x * 3.0 + time * 1.5) * cos(pos.z * 2.0 + time * 1.0) * 0.05; float wave2 = sin(pos.x * 5.0 - time * 2.0) * cos(pos.z * 4.0 + time * 1.3) * 0.03; pos.y += wave1 + wave2; gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0); } `; const WATER_FRAGMENT_SHADER = ` varying vec2 vUv; uniform float time; uniform float reflectivity; void main() { // 基础镜面颜色 vec3 baseColor = vec3(0.4, 0.6, 0.8); // 水波纹图案 float wave = sin(vUv.x * 20.0 + time * 2.0) * cos(vUv.y * 20.0 + time * 1.5); wave = wave * 0.5 + 0.5; // 边缘高光 float edge = smoothstep(0.0, 0.1, min(min(vUv.x, 1.0 - vUv.x), min(vUv.y, 1.0 - vUv.y))); vec3 color = mix(baseColor, vec3(0.7, 0.9, 1.0), wave * 0.4); float alpha = reflectivity * edge * (0.5 + wave * 0.2); gl_FragColor = vec4(color, alpha); } `; /** 发光线条着色器 - 知识图谱连线 */ const GLOW_LINE_VERTEX_SHADER = ` varying float vAlpha; void main() { vAlpha = 1.0; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `; const GLOW_LINE_FRAGMENT_SHADER = ` uniform vec3 color; uniform float opacity; varying float vAlpha; void main() { gl_FragColor = vec4(color, opacity * vAlpha); } `; /* ========================================================================= * 辅助数据结构 * ========================================================================= */ /** 力导向布局引擎 (简化版) */ class ForceLayout3D { /** * @param {Object} params * @param {number} params.repulsion - 排斥力系数 * @param {number} params.attraction - 吸引力系数 * @param {number} params.damping - 阻尼系数 * @param {number} params.iterations - 每次更新的迭代次数 */ constructor(params = {}) { this.repulsion = params.repulsion || 50; this.attraction = params.attraction || 0.01; this.damping = params.damping || 0.9; this.iterations = params.iterations || 3; this.nodes = new Map(); this.edges = []; this.velocities = new Map(); } /** 添加节点 */ addNode(id, position) { this.nodes.set(id, position.clone()); this.velocities.set(id, new THREE.Vector3()); } /** 添加边 */ addEdge(sourceId, targetId, weight = 1.0) { this.edges.push({ source: sourceId, target: targetId, weight }); } /** 清除所有节点和边 */ clear() { this.nodes.clear(); this.edges = []; this.velocities.clear(); } /** 执行一步布局计算 */ step() { const nodeKeys = Array.from(this.nodes.keys()); for (let iter = 0; iter < this.iterations; iter++) { // 排斥力 - 所有节点互相排斥 for (let i = 0; i < nodeKeys.length; i++) { for (let j = i + 1; j < nodeKeys.length; j++) { const posA = this.nodes.get(nodeKeys[i]); const posB = this.nodes.get(nodeKeys[j]); const diff = new THREE.Vector3().subVectors(posA, posB); const dist = diff.length() || 0.01; const force = this.repulsion / (dist * dist); const forceVec = diff.normalize().multiplyScalar(force); this.velocities.get(nodeKeys[i]).add(forceVec); this.velocities.get(nodeKeys[j]).sub(forceVec); } } // 吸引力 - 连接的节点相互吸引 for (const edge of this.edges) { const posA = this.nodes.get(edge.source); const posB = this.nodes.get(edge.target); if (!posA || !posB) continue; const diff = new THREE.Vector3().subVectors(posB, posA); const dist = diff.length(); const force = dist * this.attraction * edge.weight; const forceVec = diff.normalize().multiplyScalar(force); this.velocities.get(edge.source).add(forceVec); this.velocities.get(edge.target).sub(forceVec); } // 应用速度和阻尼 for (const [id, vel] of this.velocities) { vel.multiplyScalar(this.damping); this.nodes.get(id).add(vel); } } return this.nodes; } /** 获取节点位置 */ getPositions() { const positions = {}; for (const [id, pos] of this.nodes) { positions[id] = pos.clone(); } return positions; } } /** 粒子爆炸特效管理器 */ class ParticleExplosion { /** * @param {THREE.Vector3} origin - 爆炸原点 * @param {number} color - 粒子颜色 * @param {number} count - 粒子数量 * @param {number} duration - 持续时间(秒) */ constructor(origin, color = 0xFFD700, count = 200, duration = 2.0) { this.origin = origin.clone(); this.color = color; this.count = count; this.duration = duration; this.elapsed = 0; this.active = true; this.mesh = null; this._create(); } /** 创建粒子系统 */ _create() { const geometry = new THREE.BufferGeometry(); const positions = new Float32Array(this.count * 3); const velocities = new Float32Array(this.count * 3); const sizes = new Float32Array(this.count); const alphas = new Float32Array(this.count); const colors = new Float32Array(this.count * 3); const baseColor = new THREE.Color(this.color); for (let i = 0; i < this.count; i++) { const i3 = i * 3; // 从原点向外发射 positions[i3] = this.origin.x; positions[i3 + 1] = this.origin.y; positions[i3 + 2] = this.origin.z; // 随机方向速度 const theta = Math.random() * Math.PI * 2; const phi = Math.random() * Math.PI; const speed = randomRange(2, 8); velocities[i3] = speed * Math.sin(phi) * Math.cos(theta); velocities[i3 + 1] = speed * Math.sin(phi) * Math.sin(theta); velocities[i3 + 2] = speed * Math.cos(phi); sizes[i] = randomRange(2, 6); alphas[i] = 1.0; // 颜色微小变化 colors[i3] = baseColor.r + randomRange(-0.1, 0.1); colors[i3 + 1] = baseColor.g + randomRange(-0.1, 0.1); colors[i3 + 2] = baseColor.b + randomRange(-0.1, 0.1); } geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1)); geometry.setAttribute('alpha', new THREE.BufferAttribute(alphas, 1)); geometry.setAttribute('customColor', new THREE.BufferAttribute(colors, 3)); this.velocities = velocities; const material = new THREE.ShaderMaterial({ vertexShader: PARTICLE_VERTEX_SHADER, fragmentShader: PARTICLE_FRAGMENT_SHADER, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, }); this.mesh = new THREE.Points(geometry, material); this.mesh.frustumCulled = false; } /** 更新动画 */ update(deltaTime) { if (!this.active) return; this.elapsed += deltaTime; const progress = this.elapsed / this.duration; if (progress >= 1.0) { this.active = false; return; } const positions = this.mesh.geometry.attributes.position.array; const alphas = this.mesh.geometry.attributes.alpha.array; const sizes = this.mesh.geometry.attributes.size.array; for (let i = 0; i < this.count; i++) { const i3 = i * 3; // 更新位置 positions[i3] += this.velocities[i3] * deltaTime; positions[i3 + 1] += this.velocities[i3 + 1] * deltaTime; positions[i3 + 2] += this.velocities[i3 + 2] * deltaTime; // 重力效果 this.velocities[i3 + 1] -= 3.0 * deltaTime; // 渐隐 alphas[i] = 1.0 - progress; sizes[i] *= 0.995; } this.mesh.geometry.attributes.position.needsUpdate = true; this.mesh.geometry.attributes.alpha.needsUpdate = true; this.mesh.geometry.attributes.size.needsUpdate = true; } /** 销毁 */ dispose() { if (this.mesh) { this.mesh.geometry.dispose(); this.mesh.material.dispose(); } } } /* ========================================================================= * 主组件定义:consciousness-3d-space * ========================================================================= */ /** HTML 模板 */ const COMPONENT_TEMPLATE = `
初始化意识空间...

CONSCIOUSNESS 3D SPACE

-- FPS
视图切换
全景
记忆
知识
目标
技能
情绪
社交
动画控制
动画速度 1.0x
粒子密度 100%
元素可见性
记忆星云
知识图谱
目标晶体
技能光环
情绪粒子
反思之镜
社交网络
时间回放
过去 现在
聚焦此处
高亮同类
隐藏元素
隔离此类型
查看详情
0
记忆
0
实体
0
目标
0
技能
0
连接
1-7 切换视图 | H 面板 | R 重置 | 空格 暂停
`; /* ========================================================================= * 主组件类 * ========================================================================= */ class Consciousness3DSpace extends HTMLElement { /** 组件标签名 */ static get observedAttributes() { return ['width', 'height', 'data-url']; } constructor() { super(); this.attachShadow({ mode: 'open' }); /* ---- 内部状态 ---- */ this._initialized = false; this._animationId = null; this._clock = null; this._paused = false; this._animationSpeed = 1.0; this._currentView = VIEW_MODES.ALL; this._searchQuery = ''; this._selectedObject = null; this._hoveredObject = null; this._contextTarget = null; /* ---- Three.js 核心 ---- */ this._renderer = null; this._scene = null; this._camera = null; this._raycaster = null; this._mouse = new THREE.Vector2(); this._orbitControls = null; /* ---- 可视化层 ---- */ this._layers = { memory: null, // Group knowledge: null, goals: null, skills: null, emotions: null, mirror: null, social: null, }; /* ---- 数据引用 ---- */ this._data = { memories: [], entities: [], relations: [], goals: [], skills: [], emotions: [], users: [], connections: [], }; /* ---- 力导向布局引擎 ---- */ this._forceLayout = new ForceLayout3D(); /* ---- 爆炸特效列表 ---- */ this._explosions = []; /* ---- FPS 计算 ---- */ this._frameCount = 0; this._lastFpsTime = 0; /* ---- 时间轴 ---- */ this._timelineSnapshots = []; this._timelineIndex = 0; /* ---- 可交互对象缓存 ---- */ this._interactableObjects = []; /* ---- 绑定事件处理 ---- */ this._onResize = this._onResize.bind(this); this._onClick = this._onClick.bind(this); this._onMouseMove = this._onMouseMove.bind(this); this._onContextMenu = this._onContextMenu.bind(this); this._onKeyDown = this._onKeyDown.bind(this); this._animate = this._animate.bind(this); } /* ========================================================================= * Web Component 生命周期 * ========================================================================= */ connectedCallback() { // 注入 Shadow DOM 内容 this.shadowRoot.innerHTML = COMPONENT_TEMPLATE; this._init(); } disconnectedCallback() { this._dispose(); window.removeEventListener('resize', this._onResize); window.removeEventListener('keydown', this._onKeyDown); } attributeChangedCallback(name, oldVal, newVal) { if (oldVal === newVal) return; if (name === 'data-url' && this._initialized) { this._fetchData(newVal); } } /* ========================================================================= * 初始化 * ========================================================================= */ _init() { // 加载 Three.js 依赖 this._loadDependencies() .then(() => { this._initThreeJS(); this._initControls(); this._initUIBindings(); this._initSceneContent(); this._initLights(); this._generateDemoData(); this._populateVisualization(); this._startAnimation(); this._hideLoadingScreen(); this._initialized = true; }) .catch(err => { console.error('[Consciousness3DSpace] 初始化失败:', err); this._hideLoadingScreen(); }); } /** 动态加载 Three.js 依赖 */ async _loadDependencies() { const cdnBase = 'https://unpkg.com/three@0.160.0/build/'; // 检查 THREE 是否已存在 if (typeof THREE !== 'undefined') return; // 加载 Three.js 核心 await this._loadScript(cdnBase + 'three.module.js', 'module'); // 如果 CDN 模块加载失败,尝试全局 UMD 版本 if (typeof THREE === 'undefined') { await this._loadScript('https://unpkg.com/three@0.160.0/build/three.min.js'); } // 加载 OrbitControls if (typeof THREE === 'undefined') { throw new Error('Three.js 加载失败,请检查网络连接'); } // 内联实现简易 OrbitControls(避免 CDN 加载问题) this._createSimpleOrbitControls(); } /** 动态脚本加载器 */ _loadScript(url, type) { return new Promise((resolve, reject) => { // 避免重复加载 const existing = document.querySelector(`script[src="${url}"]`); if (existing) { existing.addEventListener('load', resolve); if (existing.dataset.loaded) resolve(); return; } const script = document.createElement('script'); script.src = url; if (type === 'module') { script.type = 'module'; } script.onload = () => { script.dataset.loaded = 'true'; resolve(); }; script.onerror = () => reject(new Error(`无法加载脚本: ${url}`)); document.head.appendChild(script); }); } /** 创建简易的轨道控制器(不依赖外部模块) */ _createSimpleOrbitControls() { const self = this; const canvas = this._renderer.domElement; let isDown = false; let isRight = false; let prevX = 0, prevY = 0; let theta = 0, phi = Math.PI / 3; let radius = 50; let target = new THREE.Vector3(0, 0, 0); function updateCamera() { const x = radius * Math.sin(phi) * Math.cos(theta); const y = radius * Math.cos(phi); const z = radius * Math.sin(phi) * Math.sin(theta); self._camera.position.set(target.x + x, target.y + y, target.z + z); self._camera.lookAt(target); } canvas.addEventListener('pointerdown', (e) => { if (e.button === 2) { isRight = true; } else { isDown = true; } prevX = e.clientX; prevY = e.clientY; }); canvas.addEventListener('pointermove', (e) => { if (!isDown && !isRight) return; const dx = e.clientX - prevX; const dy = e.clientY - prevY; prevX = e.clientX; prevY = e.clientY; if (isDown) { theta -= dx * 0.005; phi = Math.max(0.1, Math.min(Math.PI - 0.1, phi + dy * 0.005)); } if (isRight) { const right = new THREE.Vector3(); const up = new THREE.Vector3(0, 1, 0); right.crossVectors(self._camera.getWorldDirection(new THREE.Vector3()), up).normalize(); target.add(right.multiplyScalar(-dx * 0.05)); target.y += dy * 0.05; } updateCamera(); }); window.addEventListener('pointerup', () => { isDown = false; isRight = false; }); canvas.addEventListener('wheel', (e) => { e.preventDefault(); radius = Math.max(5, Math.min(200, radius + e.deltaY * 0.05)); updateCamera(); }, { passive: false }); // 提供公共方法 this._orbitControls = { updateCamera, setTarget: (t) => { target.copy(t); updateCamera(); }, reset: () => { theta = 0; phi = Math.PI / 3; radius = 50; target.set(0, 0, 0); updateCamera(); }, getTarget: () => target.clone(), getRadius: () => radius, focusOn: (pos, newRadius = 15) => { target.copy(pos); radius = newRadius; updateCamera(); } }; updateCamera(); } /** 初始化 Three.js 核心 */ _initThreeJS() { const container = this.shadowRoot.querySelector('#canvas-container'); // 场景 this._scene = new THREE.Scene(); this._scene.background = new THREE.Color(0x000510); this._scene.fog = new THREE.FogExp2(0x000510, 0.008); // 相机 this._camera = new THREE.PerspectiveCamera( 60, container.clientWidth / container.clientHeight, 0.1, 1000 ); // 渲染器 this._renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, powerPreference: 'high-performance', }); this._renderer.setSize(container.clientWidth, container.clientHeight); this._renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); this._renderer.toneMapping = THREE.ACESFilmicToneMapping; this._renderer.toneMappingExposure = 1.2; container.appendChild(this._renderer.domElement); // 时钟 this._clock = new THREE.Clock(); // 射线投射器(用于鼠标拾取) this._raycaster = new THREE.Raycaster(); this._raycaster.params.Points = { threshold: 0.5 }; // 事件监听 window.addEventListener('resize', this._onResize); this._renderer.domElement.addEventListener('click', this._onClick); this._renderer.domElement.addEventListener('pointermove', this._onMouseMove); this._renderer.domElement.addEventListener('contextmenu', this._onContextMenu); window.addEventListener('keydown', this._onKeyDown); } /** 初始化场景光源 */ _initLights() { // 环境光 - 微弱的整体照明 const ambient = new THREE.AmbientLight(0x1a1a2e, 0.3); this._scene.add(ambient); // 中心点光源 - 模拟意识核心 const coreLight = new THREE.PointLight(0x4488ff, 2, 80); coreLight.position.set(0, 0, 0); this._scene.add(coreLight); this._coreLight = coreLight; // 半球光 - 天空/地面色彩 const hemiLight = new THREE.HemisphereLight(0x2244aa, 0x112211, 0.4); this._scene.add(hemiLight); // 背景星空粒子 this._createBackgroundStars(); } /** 创建背景星空 */ _createBackgroundStars() { const count = 3000; const positions = new Float32Array(count * 3); const sizes = new Float32Array(count); for (let i = 0; i < count; i++) { const i3 = i * 3; positions[i3] = randomRange(-300, 300); positions[i3 + 1] = randomRange(-300, 300); positions[i3 + 2] = randomRange(-300, 300); sizes[i] = randomRange(0.3, 1.5); } const geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1)); // 简单的点材质 const material = new THREE.PointsMaterial({ color: 0xaaccff, size: 0.5, transparent: true, opacity: 0.4, sizeAttenuation: true, blending: THREE.AdditiveBlending, depthWrite: false, }); const stars = new THREE.Points(geometry, material); stars.frustumCulled = false; this._scene.add(stars); this._bgStars = stars; } /* ========================================================================= * 场景内容初始化 * ========================================================================= */ /** 初始化各可视化层的容器 */ _initSceneContent() { this._layers.memory = new THREE.Group(); this._layers.memory.name = 'memory'; this._scene.add(this._layers.memory); this._layers.knowledge = new THREE.Group(); this._layers.knowledge.name = 'knowledge'; this._scene.add(this._layers.knowledge); this._layers.goals = new THREE.Group(); this._layers.goals.name = 'goals'; this._scene.add(this._layers.goals); this._layers.skills = new THREE.Group(); this._layers.skills.name = 'skills'; this._scene.add(this._layers.skills); this._layers.emotions = new THREE.Group(); this._layers.emotions.name = 'emotions'; this._scene.add(this._layers.emotions); this._layers.mirror = new THREE.Group(); this._layers.mirror.name = 'mirror'; this._scene.add(this._layers.mirror); this._layers.social = new THREE.Group(); this._layers.social.name = 'social'; this._scene.add(this._layers.social); } /* ========================================================================= * 数据生成与填充 * ========================================================================= */ /** 生成演示数据 */ _generateDemoData() { // ---- 记忆数据 ---- const memoryTopics = [ '第一次学习编程', '与朋友的深夜对话', '读完《三体》', '解决复杂算法', '观看日出', '收到重要邮件', '项目上线成功', '一次失败的演讲', '与导师的交流', '创作第一首诗', '探索新城市', '帮助陌生人', '调试通宵的bug', '收到生日祝福', '学到新知识', '做出重要决定', '运动突破记录', '品尝新美食', '观看纪录片', '参与开源项目', '团队庆祝活动', '独立完成设计', '阅读科学论文', '音乐会上的感动', '冥想中的顿悟', '代码重构完成', '设计原型被认可', '数据分析发现', '与AI对话的启发', '回顾旧日记', '清晨的跑步', '家庭视频通话', ]; this._data.memories = memoryTopics.map((title, i) => { const importance = Math.random(); const sentiment = randomRange(-1, 1); // -1=负面, 0=中性, 1=正面 const accessCount = Math.floor(randomRange(1, 50)); // 使用简化的降维位置(模拟 t-SNE/PCA) const angle1 = (i / memoryTopics.length) * Math.PI * 2; const angle2 = randomRange(0, Math.PI); const radius = randomRange(8, 25); return { id: `mem_${i}`, title, content: `关于"${title}"的详细记忆内容。时间:2024-${String(Math.floor(randomRange(1, 13))).padStart(2, '0')}-${String(Math.floor(randomRange(1, 29))).padStart(2, '0')}`, importance, sentiment, accessCount, position: new THREE.Vector3( radius * Math.sin(angle2) * Math.cos(angle1), radius * Math.sin(angle2) * Math.sin(angle1), radius * Math.cos(angle2) ), tags: ['记忆', sentiment > 0.3 ? '积极' : sentiment < -0.3 ? '消极' : '中性'], type: 'memory', }; }); // ---- 知识图谱数据 ---- const entityNames = [ '人工智能', '神经网络', '深度学习', '自然语言处理', '计算机视觉', '强化学习', '注意力机制', '变换器', '知识图谱', '机器学习', 'Python', 'JavaScript', 'Three.js', '数据结构', '算法', '物理', '数学', '哲学', '心理学', '认知科学', ]; const entityTypes = Object.keys(ENTITY_TYPE_COLORS); this._data.entities = entityNames.map((name, i) => ({ id: `ent_${i}`, name, type: entityTypes[i % entityTypes.length], connections: Math.floor(randomRange(2, 12)), description: `"${name}"是知识体系中的重要概念节点。`, position: new THREE.Vector3( randomRange(-30, 30), randomRange(-20, 20), randomRange(-30, 30) ), })); // 生成关系 this._data.relations = []; for (let i = 0; i < entityNames.length; i++) { const numRelations = Math.floor(randomRange(1, 4)); for (let j = 0; j < numRelations; j++) { const target = Math.floor(Math.random() * entityNames.length); if (target !== i) { this._data.relations.push({ source: `ent_${i}`, target: `ent_${target}`, weight: randomRange(0.3, 1.0), label: '相关', }); } } } // 初始化力导向布局 this._forceLayout.clear(); this._data.entities.forEach(e => this._forceLayout.addNode(e.id, e.position)); this._data.relations.forEach(r => this._forceLayout.addEdge(r.source, r.target, r.weight)); // 运行多次迭代使布局收敛 for (let i = 0; i < 50; i++) this._forceLayout.step(); // 更新实体位置 const positions = this._forceLayout.getPositions(); this._data.entities.forEach(e => { if (positions[e.id]) e.position.copy(positions[e.id]); }); // ---- 目标数据 ---- this._data.goals = [ { id: 'goal_0', title: '构建完整意识系统', state: 'active', progress: 0.65, children: [ { id: 'goal_0_0', title: '记忆模块', state: 'completed', progress: 1.0 }, { id: 'goal_0_1', title: '知识图谱模块', state: 'active', progress: 0.8 }, { id: 'goal_0_2', title: '情绪系统', state: 'active', progress: 0.5 }, ]}, { id: 'goal_1', title: '学习新技能', state: 'active', progress: 0.4, children: [ { id: 'goal_1_0', title: '掌握3D可视化', state: 'active', progress: 0.7 }, { id: 'goal_1_1', title: '学习音乐创作', state: 'paused', progress: 0.2 }, ]}, { id: 'goal_2', title: '提升社交智能', state: 'active', progress: 0.3, children: [] }, { id: 'goal_3', title: '完成日常任务', state: 'completed', progress: 1.0, children: [] }, { id: 'goal_4', title: '探索未知领域', state: 'paused', progress: 0.1, children: [] }, ]; // ---- 技能数据 ---- this._data.skills = [ { id: 'skill_0', name: '编程', type: 'technical', proficiency: 0.85 }, { id: 'skill_1', name: '写作', type: 'creative', proficiency: 0.72 }, { id: 'skill_2', name: '分析', type: 'analytical', proficiency: 0.88 }, { id: 'skill_3', name: '沟通', type: 'social', proficiency: 0.65 }, { id: 'skill_4', name: '设计', type: 'creative', proficiency: 0.55 }, { id: 'skill_5', name: '数学', type: 'analytical', proficiency: 0.78 }, { id: 'skill_6', name: '学习', type: 'default', proficiency: 0.90 }, { id: 'skill_7', name: '推理', type: 'analytical', proficiency: 0.82 }, ]; // ---- 情绪数据 ---- this._data.emotions = [ { type: 'joy', intensity: 0.7 }, { type: 'curiosity', intensity: 0.9 }, { type: 'sadness', intensity: 0.15 }, { type: 'anger', intensity: 0.05 }, ]; // ---- 社交数据 ---- this._data.users = [ { id: 'user_0', name: 'Alice', closeness: 0.9, role: '核心用户' }, { id: 'user_1', name: 'Bob', closeness: 0.7, role: '开发者' }, { id: 'user_2', name: 'Carol', closeness: 0.5, role: '研究员' }, { id: 'user_3', name: 'David', closeness: 0.6, role: '设计师' }, { id: 'user_4', name: 'Eve', closeness: 0.3, role: '访客' }, ]; this._data.connections = [ { source: 'user_0', target: 'user_1', strength: 0.8 }, { source: 'user_0', target: 'user_2', strength: 0.5 }, { source: 'user_1', target: 'user_3', strength: 0.6 }, { source: 'user_2', target: 'user_4', strength: 0.3 }, ]; } /* ========================================================================= * 可视化元素构建 * ========================================================================= */ /** 填充所有可视化层 */ _populateVisualization() { this._buildMemoryNebula(); this._buildKnowledgeGraph(); this._buildGoalCrystals(); this._buildSkillHalos(); this._buildEmotionParticles(); this._buildReflectionMirror(); this._buildSocialNetwork(); this._updateStats(); } /* ---- 1. 记忆星云 ---- */ _buildMemoryNebula() { const memories = this._data.memories; const count = memories.length; const positions = new Float32Array(count * 3); const sizes = new Float32Array(count); const importances = new Float32Array(count); const colors = new Float32Array(count * 3); for (let i = 0; i < count; i++) { const mem = memories[i]; const i3 = i * 3; positions[i3] = mem.position.x; positions[i3 + 1] = mem.position.y; positions[i3 + 2] = mem.position.z; // 大小 = 访问次数(归一化) sizes[i] = normalizeToRange(mem.accessCount, 1, 50, 2, 12); importances[i] = mem.importance; // 颜色 = 情绪效价 const c = new THREE.Color(); if (mem.sentiment < -0.3) { // 负面 -> 蓝色系 c.setHSL(0.6, 0.8, 0.5 + mem.importance * 0.3); } else if (mem.sentiment > 0.3) { // 正面 -> 黄色系 c.setHSL(0.12, 0.9, 0.5 + mem.importance * 0.3); } else { // 中性 -> 红色系 c.setHSL(0.0, 0.7, 0.5 + mem.importance * 0.3); } colors[i3] = c.r; colors[i3 + 1] = c.g; colors[i3 + 2] = c.b; } const geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1)); geometry.setAttribute('importance', new THREE.BufferAttribute(importances, 1)); geometry.setAttribute('customColor', new THREE.BufferAttribute(colors, 3)); const material = new THREE.ShaderMaterial({ vertexShader: STAR_VERTEX_SHADER, fragmentShader: STAR_FRAGMENT_SHADER, uniforms: { time: { value: 0 }, globalBrightness: { value: 1.0 }, }, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, }); const points = new THREE.Points(geometry, material); points.name = 'memory-nebula'; points.userData.layer = 'memory'; this._layers.memory.add(points); // 记忆间连接线(相似记忆连线) this._buildMemoryConnections(memories); // 记录可交互对象 for (let i = 0; i < count; i++) { this._interactableObjects.push({ type: 'memory', index: i, data: memories[i], layer: 'memory', object: points, }); } // 记忆星云中心辉光 const glowGeo = new THREE.SphereGeometry(2, 32, 32); const glowMat = new THREE.MeshBasicMaterial({ color: 0x4488ff, transparent: true, opacity: 0.15, blending: THREE.AdditiveBlending, }); const glow = new THREE.Mesh(glowGeo, glowMat); glow.name = 'memory-core-glow'; this._layers.memory.add(glow); } /** 构建记忆间的连接线 */ _buildMemoryConnections(memories) { const linePositions = []; const maxConnections = 40; let count = 0; for (let i = 0; i < memories.length && count < maxConnections; i++) { for (let j = i + 1; j < memories.length && count < maxConnections; j++) { const dist = memories[i].position.distanceTo(memories[j].position); if (dist < 12) { linePositions.push( memories[i].position.x, memories[i].position.y, memories[i].position.z, memories[j].position.x, memories[j].position.y, memories[j].position.z ); count++; } } } if (linePositions.length > 0) { const geo = new THREE.BufferGeometry(); geo.setAttribute('position', new THREE.Float32BufferAttribute(linePositions, 3)); const mat = new THREE.LineBasicMaterial({ color: 0x4488ff, transparent: true, opacity: 0.08, blending: THREE.AdditiveBlending, depthWrite: false, }); const lines = new THREE.LineSegments(geo, mat); lines.name = 'memory-connections'; this._layers.memory.add(lines); } } /* ---- 2. 知识图谱 ---- */ _buildKnowledgeGraph() { const entities = this._data.entities; const relations = this._data.relations; const layer = this._layers.knowledge; // 实体球体 for (let i = 0; i < entities.length; i++) { const ent = entities[i]; const radius = 0.3 + ent.connections * 0.15; const color = ENTITY_TYPE_COLORS[ent.type] || ENTITY_TYPE_COLORS.default; // 发光球体 const geo = new THREE.SphereGeometry(radius, 24, 24); const mat = new THREE.MeshPhongMaterial({ color, emissive: color, emissiveIntensity: 0.4, transparent: true, opacity: 0.85, shininess: 80, }); const mesh = new THREE.Mesh(geo, mat); mesh.position.copy(ent.position); mesh.name = ent.id; mesh.userData = { type: 'entity', index: i, data: ent, layer: 'knowledge' }; layer.add(mesh); // 外部辉光环 const glowGeo = new THREE.SphereGeometry(radius * 1.6, 16, 16); const glowMat = new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.08, blending: THREE.AdditiveBlending, side: THREE.BackSide, }); const glowMesh = new THREE.Mesh(glowGeo, glowMat); glowMesh.position.copy(ent.position); layer.add(glowMesh); this._interactableObjects.push({ type: 'entity', index: i, data: ent, layer: 'knowledge', object: mesh, }); } // 关系连线 const linePositions = []; const lineColors = []; for (const rel of relations) { const src = entities.find(e => e.id === rel.source); const tgt = entities.find(e => e.id === rel.target); if (!src || !tgt) continue; linePositions.push(src.position.x, src.position.y, src.position.z); linePositions.push(tgt.position.x, tgt.position.y, tgt.position.z); const c1 = new THREE.Color(ENTITY_TYPE_COLORS[src.type] || 0xffffff); const c2 = new THREE.Color(ENTITY_TYPE_COLORS[tgt.type] || 0xffffff); lineColors.push(c1.r, c1.g, c1.b); lineColors.push(c2.r, c2.g, c2.b); } if (linePositions.length > 0) { const geo = new THREE.BufferGeometry(); geo.setAttribute('position', new THREE.Float32BufferAttribute(linePositions, 3)); geo.setAttribute('color', new THREE.Float32BufferAttribute(lineColors, 3)); const mat = new THREE.LineBasicMaterial({ vertexColors: true, transparent: true, opacity: 0.25, blending: THREE.AdditiveBlending, depthWrite: false, }); const lines = new THREE.LineSegments(geo, mat); lines.name = 'knowledge-relations'; layer.add(lines); } } /* ---- 3. 目标晶体 ---- */ _buildGoalCrystals() { const goals = this._data.goals; const layer = this._layers.goals; const self = this; goals.forEach((goal, gi) => { // 父目标位置 - 环形分布 const parentAngle = (gi / goals.length) * Math.PI * 2; const parentRadius = 15; const parentPos = new THREE.Vector3( Math.cos(parentAngle) * parentRadius, randomRange(-3, 3), Math.sin(parentAngle) * parentRadius ); self._createCrystalMesh(goal, parentPos, layer, gi, 1.5); // 子目标围绕父目标旋转 if (goal.children) { goal.children.forEach((child, ci) => { const childAngle = (ci / goal.children.length) * Math.PI * 2; const childRadius = 3; const childPos = new THREE.Vector3( parentPos.x + Math.cos(childAngle) * childRadius, parentPos.y + randomRange(-1, 1), parentPos.z + Math.sin(childAngle) * childRadius ); self._createCrystalMesh(child, childPos, layer, gi * 100 + ci, 0.8, parentPos); }); } }); } /** 创建单个晶体网格 */ _createCrystalMesh(goal, position, layer, index, scale = 1.0, orbitCenter = null) { const color = GOAL_STATE_COLORS[goal.state] || 0x888888; // 根据进度选择多面体 let geometry; if (goal.progress >= 0.8) { geometry = new THREE.IcosahedronGeometry(scale, 0); } else { geometry = new THREE.DodecahedronGeometry(scale, 0); } const material = new THREE.MeshPhongMaterial({ color, emissive: color, emissiveIntensity: 0.3, transparent: true, opacity: 0.3 + goal.progress * 0.6, shininess: 120, side: THREE.DoubleSide, wireframe: false, }); const mesh = new THREE.Mesh(geometry, material); mesh.position.copy(position); mesh.name = goal.id; mesh.userData = { type: 'goal', index, data: goal, layer: 'goals', orbitCenter, orbitAngle: Math.random() * Math.PI * 2, orbitSpeed: 0.2 + Math.random() * 0.3, rotationSpeed: new THREE.Vector3( randomRange(-0.5, 0.5), randomRange(-0.5, 0.5), randomRange(-0.5, 0.5) ), }; layer.add(mesh); // 晶体边框线 const wireGeo = new THREE.EdgesGeometry(geometry); const wireMat = new THREE.LineBasicMaterial({ color, transparent: true, opacity: 0.4, }); const wireframe = new THREE.LineSegments(wireGeo, wireMat); mesh.add(wireframe); // 添加光晕 const glowGeo = new THREE.SphereGeometry(scale * 1.5, 12, 12); const glowMat = new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.06, blending: THREE.AdditiveBlending, side: THREE.BackSide, }); const glow = new THREE.Mesh(glowGeo, glowMat); mesh.add(glow); this._interactableObjects.push({ type: 'goal', index, data: goal, layer: 'goals', object: mesh, }); return mesh; } /* ---- 4. 技能光环 ---- */ _buildSkillHalos() { const skills = this._data.skills; const layer = this._layers.skills; skills.forEach((skill, i) => { const angle = (i / skills.length) * Math.PI * 2; const ringRadius = 12; const pos = new THREE.Vector3( Math.cos(angle) * ringRadius, randomRange(-2, 2), Math.sin(angle) * ringRadius ); // 熟练度 -> 圆环半径 const torusRadius = 0.8 + skill.proficiency * 1.5; const tubeRadius = 0.05 + skill.proficiency * 0.12; const color = SKILL_TYPE_COLORS[skill.type] || SKILL_TYPE_COLORS.default; const geo = new THREE.TorusGeometry(torusRadius, tubeRadius, 16, 48); const mat = new THREE.MeshPhongMaterial({ color, emissive: color, emissiveIntensity: 0.5, transparent: true, opacity: 0.7, shininess: 100, }); const mesh = new THREE.Mesh(geo, mat); mesh.position.copy(pos); mesh.rotation.x = Math.PI / 2 + randomRange(-0.3, 0.3); mesh.name = skill.id; mesh.userData = { type: 'skill', index: i, data: skill, layer: 'skills', pulsePhase: Math.random() * Math.PI * 2, isPulsing: false, baseEmissiveIntensity: 0.5, }; layer.add(mesh); // 外部辉光 const glowGeo = new THREE.TorusGeometry(torusRadius, tubeRadius * 3, 16, 48); const glowMat = new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.08, blending: THREE.AdditiveBlending, side: THREE.DoubleSide, }); const glow = new THREE.Mesh(glowGeo, glowMat); mesh.add(glow); this._interactableObjects.push({ type: 'skill', index: i, data: skill, layer: 'skills', object: mesh, }); }); } /* ---- 5. 情绪粒子 ---- */ _buildEmotionParticles() { const emotions = this._data.emotions; const layer = this._layers.emotions; emotions.forEach(emotion => { const particleCount = Math.floor(emotion.intensity * 300); if (particleCount < 5) return; const positions = new Float32Array(particleCount * 3); const sizes = new Float32Array(particleCount); const alphas = new Float32Array(particleCount); const colors = new Float32Array(particleCount * 3); const baseColor = new THREE.Color(EMOTION_COLORS[emotion.type] || 0xffffff); for (let i = 0; i < particleCount; i++) { const i3 = i * 3; positions[i3] = randomRange(-20, 20); positions[i3 + 1] = randomRange(-15, 15); positions[i3 + 2] = randomRange(-20, 20); sizes[i] = randomRange(1, 4); alphas[i] = randomRange(0.3, 0.9); colors[i3] = baseColor.r + randomRange(-0.05, 0.05); colors[i3 + 1] = baseColor.g + randomRange(-0.05, 0.05); colors[i3 + 2] = baseColor.b + randomRange(-0.05, 0.05); } const geo = new THREE.BufferGeometry(); geo.setAttribute('position', new THREE.BufferAttribute(positions, 3)); geo.setAttribute('size', new THREE.BufferAttribute(sizes, 1)); geo.setAttribute('alpha', new THREE.BufferAttribute(alphas, 1)); geo.setAttribute('customColor', new THREE.BufferAttribute(colors, 3)); const mat = new THREE.ShaderMaterial({ vertexShader: PARTICLE_VERTEX_SHADER, fragmentShader: PARTICLE_FRAGMENT_SHADER, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, }); const points = new THREE.Points(geo, mat); points.name = `emotion-${emotion.type}`; points.userData = { layer: 'emotions', emotionType: emotion.type, intensity: emotion.intensity, particleCount, }; layer.add(points); }); } /* ---- 6. 反思之镜 ---- */ _buildReflectionMirror() { const layer = this._layers.mirror; // 主镜面平面 const mirrorGeo = new THREE.PlaneGeometry(40, 40, 64, 64); const mirrorMat = new THREE.ShaderMaterial({ vertexShader: WATER_VERTEX_SHADER, fragmentShader: WATER_FRAGMENT_SHADER, uniforms: { time: { value: 0 }, reflectivity: { value: 0.4 }, }, transparent: true, side: THREE.DoubleSide, depthWrite: false, }); const mirror = new THREE.Mesh(mirrorGeo, mirrorMat); mirror.rotation.x = -Math.PI / 2; mirror.position.y = -12; mirror.name = 'reflection-mirror'; mirror.userData = { layer: 'mirror' }; layer.add(mirror); // 边框光圈 const ringGeo = new THREE.RingGeometry(19.5, 20.5, 64); const ringMat = new THREE.MeshBasicMaterial({ color: 0x4488ff, transparent: true, opacity: 0.15, side: THREE.DoubleSide, blending: THREE.AdditiveBlending, }); const ring = new THREE.Mesh(ringGeo, ringMat); ring.rotation.x = -Math.PI / 2; ring.position.y = -11.95; layer.add(ring); this._mirrorMaterial = mirrorMat; } /* ---- 7. 社交网络 ---- */ _buildSocialNetwork() { const users = this._data.users; const connections = this._data.connections; const layer = this._layers.social; const userPositions = {}; // 用户节点 users.forEach((user, i) => { const angle = (i / users.length) * Math.PI * 2; const r = 8; const pos = new THREE.Vector3( Math.cos(angle) * r, randomRange(-3, 3) + 10, Math.sin(angle) * r ); userPositions[user.id] = pos; // 人脸图标 - 用球体模拟 const sphereRadius = 0.5 + user.closeness * 0.5; const geo = new THREE.SphereGeometry(sphereRadius, 24, 24); const mat = new THREE.MeshPhongMaterial({ color: 0x42A5F5, emissive: 0x1565C0, emissiveIntensity: 0.3, transparent: true, opacity: 0.8, }); const mesh = new THREE.Mesh(geo, mat); mesh.position.copy(pos); mesh.name = user.id; mesh.userData = { type: 'user', index: i, data: user, layer: 'social' }; layer.add(mesh); // 眼睛(两个小球) const eyeGeo = new THREE.SphereGeometry(sphereRadius * 0.12, 8, 8); const eyeMat = new THREE.MeshBasicMaterial({ color: 0xffffff }); const eyeL = new THREE.Mesh(eyeGeo, eyeMat); eyeL.position.set(-sphereRadius * 0.3, sphereRadius * 0.15, sphereRadius * 0.85); mesh.add(eyeL); const eyeR = new THREE.Mesh(eyeGeo, eyeMat); eyeR.position.set(sphereRadius * 0.3, sphereRadius * 0.15, sphereRadius * 0.85); mesh.add(eyeR); // 瞳孔 const pupilGeo = new THREE.SphereGeometry(sphereRadius * 0.06, 8, 8); const pupilMat = new THREE.MeshBasicMaterial({ color: 0x000000 }); const pupilL = new THREE.Mesh(pupilGeo, pupilMat); pupilL.position.z = sphereRadius * 0.02; eyeL.add(pupilL); const pupilR = new THREE.Mesh(pupilGeo, pupilMat); pupilR.position.z = sphereRadius * 0.02; eyeR.add(pupilR); // 光晕 const glowGeo = new THREE.SphereGeometry(sphereRadius * 2, 12, 12); const glowMat = new THREE.MeshBasicMaterial({ color: 0x42A5F5, transparent: true, opacity: 0.05, blending: THREE.AdditiveBlending, side: THREE.BackSide, }); const glow = new THREE.Mesh(glowGeo, glowMat); mesh.add(glow); this._interactableObjects.push({ type: 'user', index: i, data: user, layer: 'social', object: mesh, }); }); // 关系连线 const linePositions = []; connections.forEach(conn => { const src = userPositions[conn.source]; const tgt = userPositions[conn.target]; if (!src || !tgt) return; linePositions.push(src.x, src.y, src.z); linePositions.push(tgt.x, tgt.y, tgt.z); }); if (linePositions.length > 0) { const geo = new THREE.BufferGeometry(); geo.setAttribute('position', new THREE.Float32BufferAttribute(linePositions, 3)); const mat = new THREE.LineBasicMaterial({ color: 0x64B5F6, transparent: true, opacity: 0.3, blending: THREE.AdditiveBlending, }); const lines = new THREE.LineSegments(geo, mat); lines.name = 'social-connections'; layer.add(lines); } } /* ========================================================================= * 动画循环 * ========================================================================= */ /** 启动动画循环 */ _startAnimation() { this._lastFpsTime = performance.now(); this._animate(); } /** 主动画帧 */ _animate() { this._animationId = requestAnimationFrame(this._animate); if (this._paused) return; const delta = this._clock.getDelta() * this._animationSpeed; const elapsed = this._clock.elapsedTime * this._animationSpeed; // 更新 FPS this._frameCount++; const now = performance.now(); if (now - this._lastFpsTime >= 1000) { const fps = Math.round(this._frameCount * 1000 / (now - this._lastFpsTime)); const fpsEl = this.shadowRoot.querySelector('#fps-counter'); if (fpsEl) fpsEl.textContent = `${fps} FPS`; this._frameCount = 0; this._lastFpsTime = now; } // 更新各层动画 this._updateMemoryAnimation(elapsed, delta); this._updateKnowledgeAnimation(elapsed, delta); this._updateGoalAnimation(elapsed, delta); this._updateSkillAnimation(elapsed, delta); this._updateEmotionAnimation(elapsed, delta); this._updateMirrorAnimation(elapsed, delta); this._updateSocialAnimation(elapsed, delta); this._updateExplosions(delta); this._updateCoreLight(elapsed); this._updateBackgroundStars(elapsed); // 渲染 this._renderer.render(this._scene, this._camera); } /** 记忆星云动画 - 星辰呼吸闪烁(着色器内处理),中心辉光脉动 */ _updateMemoryAnimation(elapsed, delta) { const nebula = this._layers.memory?.getObjectByName('memory-nebula'); if (nebula?.material?.uniforms) { nebula.material.uniforms.time.value = elapsed; } const coreGlow = this._layers.memory?.getObjectByName('memory-core-glow'); if (coreGlow) { coreGlow.scale.setScalar(1 + 0.15 * Math.sin(elapsed * 1.5)); } } /** 知识图谱动画 - 节点微弱脉动 */ _updateKnowledgeAnimation(elapsed, delta) { this._layers.knowledge?.children.forEach(child => { if (child.userData?.type === 'entity') { child.material.emissiveIntensity = 0.3 + 0.15 * Math.sin(elapsed * 2 + child.position.x); } }); } /** 目标晶体动画 - 旋转和子目标轨道运动 */ _updateGoalAnimation(elapsed, delta) { this._layers.goals?.children.forEach(child => { if (!child.userData?.type) return; // 自身旋转 const rs = child.userData.rotationSpeed; if (rs) { child.rotation.x += rs.x * delta; child.rotation.y += rs.y * delta; child.rotation.z += rs.z * delta; } // 子目标轨道运动 const center = child.userData.orbitCenter; if (center) { const angle = (child.userData.orbitAngle || 0) + elapsed * (child.userData.orbitSpeed || 0.2); const orbitR = 3; child.position.x = center.x + Math.cos(angle) * orbitR; child.position.z = center.z + Math.sin(angle) * orbitR; child.position.y = center.y + Math.sin(angle * 0.7) * 0.5; } }); } /** 技能光环动画 - 激活脉冲效果 */ _updateSkillAnimation(elapsed, delta) { this._layers.skills?.children.forEach(child => { if (!child.userData?.type) return; const phase = child.userData.pulsePhase || 0; // 持续微弱旋转 child.rotation.z += 0.3 * delta; // 脉冲效果 if (child.userData.isPulsing) { child.material.emissiveIntensity = 0.8 + 0.5 * Math.sin(elapsed * 5 + phase); child.scale.setScalar(1 + 0.1 * Math.sin(elapsed * 3 + phase)); } else { child.material.emissiveIntensity = child.userData.baseEmissiveIntensity + 0.1 * Math.sin(elapsed * 1.5 + phase); } }); } /** 情绪粒子动画 - 不同情绪不同运动模式 */ _updateEmotionAnimation(elapsed, delta) { this._layers.emotions?.children.forEach(child => { if (!child.userData?.emotionType) return; const positions = child.geometry.attributes.position.array; const count = child.userData.particleCount; const type = child.userData.emotionType; for (let i = 0; i < count; i++) { const i3 = i * 3; switch (type) { case 'joy': // 金色上浮粒子 positions[i3 + 1] += delta * 2; if (positions[i3 + 1] > 15) positions[i3 + 1] = -15; positions[i3] += Math.sin(elapsed + i) * delta * 0.3; break; case 'sadness': // 蓝色下沉粒子 positions[i3 + 1] -= delta * 1.5; if (positions[i3 + 1] < -15) positions[i3 + 1] = 15; positions[i3] += Math.cos(elapsed * 0.5 + i) * delta * 0.2; break; case 'anger': // 红色快速粒子 positions[i3] += Math.sin(elapsed * 3 + i * 0.1) * delta * 3; positions[i3 + 1] += Math.cos(elapsed * 4 + i * 0.2) * delta * 2; positions[i3 + 2] += Math.sin(elapsed * 2 + i * 0.3) * delta * 2.5; // 边界约束 for (let j = 0; j < 3; j++) { if (Math.abs(positions[i3 + j]) > 20) positions[i3 + j] *= -0.9; } break; case 'curiosity': // 绿色旋转粒子 const cx = positions[i3], cz = positions[i3 + 2]; const dist = Math.sqrt(cx * cx + cz * cz) || 1; positions[i3] += (-cz / dist) * delta * 1.5; positions[i3 + 2] += (cx / dist) * delta * 1.5; positions[i3 + 1] += Math.sin(elapsed + i * 0.5) * delta * 0.5; break; default: // 默认缓慢漂浮 positions[i3] += Math.sin(elapsed + i) * delta * 0.3; positions[i3 + 1] += Math.cos(elapsed * 0.7 + i) * delta * 0.2; break; } } child.geometry.attributes.position.needsUpdate = true; }); } /** 反思之镜动画 - 水波纹效果(着色器处理) */ _updateMirrorAnimation(elapsed, delta) { if (this._mirrorMaterial?.uniforms) { this._mirrorMaterial.uniforms.time.value = elapsed; } } /** 社交网络动画 - 节点微弱漂浮 */ _updateSocialAnimation(elapsed, delta) { this._layers.social?.children.forEach(child => { if (child.userData?.type === 'user') { const base = child.position.clone(); child.position.y += Math.sin(elapsed * 0.8 + child.position.x) * delta * 0.2; } }); } /** 更新爆炸特效 */ _updateExplosions(delta) { for (let i = this._explosions.length - 1; i >= 0; i--) { const exp = this._explosions[i]; exp.update(delta); if (!exp.active) { this._layers.goals.remove(exp.mesh); exp.dispose(); this._explosions.splice(i, 1); } } } /** 核心光源呼吸效果 */ _updateCoreLight(elapsed) { if (this._coreLight) { this._coreLight.intensity = 1.5 + 0.5 * Math.sin(elapsed * 0.8); } } /** 背景星空缓慢旋转 */ _updateBackgroundStars(elapsed) { if (this._bgStars) { this._bgStars.rotation.y = elapsed * 0.01; this._bgStars.rotation.x = Math.sin(elapsed * 0.005) * 0.02; } } /* ========================================================================= * 交互功能 * ========================================================================= */ /** 鼠标点击事件 */ _onClick(event) { const rect = this._renderer.domElement.getBoundingClientRect(); this._mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; this._mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; this._raycaster.setFromCamera(this._mouse, this._camera); const intersects = this._raycaster.intersectObjects(this._scene.children, true); // 关闭右键菜单 this._hideContextMenu(); if (intersects.length > 0) { const hit = intersects[0].object; const userData = hit.userData; if (userData && userData.type) { this._selectedObject = userData; this._showTooltipFor(userData, event); return; } } this._hideTooltip(); this._selectedObject = null; } /** 鼠标移动事件(悬停检测) */ _onMouseMove(event) { const rect = this._renderer.domElement.getBoundingClientRect(); this._mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; this._mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; // 更新 tooltip 位置(如果已显示) const tooltip = this.shadowRoot.querySelector('#tooltip'); if (tooltip.classList.contains('visible')) { tooltip.style.left = (event.clientX - rect.left + 15) + 'px'; tooltip.style.top = (event.clientY - rect.top - 10) + 'px'; } // 悬停高亮(节流处理) if (this._hoverThrottle) return; this._hoverThrottle = true; setTimeout(() => { this._hoverThrottle = false; }, 100); this._raycaster.setFromCamera(this._mouse, this._camera); const intersects = this._raycaster.intersectObjects(this._scene.children, true); // 取消之前的高亮 if (this._hoveredObject && this._hoveredObject !== this._selectedObject) { this._unhighlightObject(this._hoveredObject); } if (intersects.length > 0) { const hit = intersects[0].object; const userData = hit.userData; if (userData && userData.type && userData !== this._selectedObject) { this._hoveredObject = userData; this._highlightObject(userData); } } else { this._hoveredObject = null; } } /** 右键菜单事件 */ _onContextMenu(event) { event.preventDefault(); const rect = this._renderer.domElement.getBoundingClientRect(); this._mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; this._mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; this._raycaster.setFromCamera(this._mouse, this._camera); const intersects = this._raycaster.intersectObjects(this._scene.children, true); if (intersects.length > 0) { const hit = intersects[0].object; if (hit.userData?.type) { this._contextTarget = hit.userData; this._showContextMenu(event.clientX - rect.left, event.clientY - rect.top); return; } } this._hideContextMenu(); } /** 键盘快捷键 */ _onKeyDown(event) { const key = event.key; // 忽略搜索框内的输入 const searchBox = this.shadowRoot.querySelector('#search-box'); if (searchBox && this.shadowRoot.activeElement === searchBox) return; switch (key) { case '1': this._switchView(VIEW_MODES.MEMORY); break; case '2': this._switchView(VIEW_MODES.KNOWLEDGE); break; case '3': this._switchView(VIEW_MODES.GOALS); break; case '4': this._switchView(VIEW_MODES.SKILLS); break; case '5': this._switchView(VIEW_MODES.EMOTIONS); break; case '6': this._switchView(VIEW_MODES.SOCIAL); break; case '7': this._switchView(VIEW_MODES.PANORAMIC); break; case 'h': case 'H': this._togglePanel(); break; case 'r': case 'R': this._orbitControls?.reset(); break; case ' ': event.preventDefault(); this._paused = !this._paused; break; case 'Escape': this._hideContextMenu(); this._hideTooltip(); break; } } /** 窗口大小变化处理 */ _onResize() { const container = this.shadowRoot.querySelector('#canvas-container'); if (!container || !this._renderer || !this._camera) return; const w = container.clientWidth; const h = container.clientHeight; this._camera.aspect = w / h; this._camera.updateProjectionMatrix(); this._renderer.setSize(w, h); } /* ========================================================================= * UI 交互 * ========================================================================= */ /** 初始化 UI 事件绑定 */ _initUIBindings() { const root = this.shadowRoot; // 视图切换按钮 root.querySelectorAll('.view-btn').forEach(btn => { btn.addEventListener('click', () => { this._switchView(btn.dataset.view); }); }); // 动画速度滑块 const speedSlider = root.querySelector('#speed-slider'); const speedValue = root.querySelector('#speed-value'); if (speedSlider) { speedSlider.addEventListener('input', () => { this._animationSpeed = parseFloat(speedSlider.value); if (speedValue) speedValue.textContent = `${this._animationSpeed.toFixed(1)}x`; }); } // 粒子密度滑块 const densitySlider = root.querySelector('#density-slider'); const densityValue = root.querySelector('#density-value'); if (densitySlider) { densitySlider.addEventListener('input', () => { const val = parseInt(densitySlider.value); if (densityValue) densityValue.textContent = `${val}%`; // 更新星云亮度作为密度的代理指标 const nebula = this._layers.memory?.getObjectByName('memory-nebula'); if (nebula?.material?.uniforms) { nebula.material.uniforms.globalBrightness.value = val / 100; } }); } // 元素可见性开关 root.querySelectorAll('.toggle-btn').forEach(btn => { btn.addEventListener('click', () => { btn.classList.toggle('on'); const layerName = btn.dataset.layer; if (this._layers[layerName]) { this._layers[layerName].visible = btn.classList.contains('on'); } }); }); // 搜索框 const searchBox = root.querySelector('#search-box'); if (searchBox) { searchBox.addEventListener('input', () => { this._searchQuery = searchBox.value.trim().toLowerCase(); this._applySearch(); }); } // 切换面板按钮 const toggleBtn = root.querySelector('#toggle-panel-btn'); if (toggleBtn) { toggleBtn.addEventListener('click', () => this._togglePanel()); } // 右键菜单项 root.querySelectorAll('.ctx-menu-item').forEach(item => { item.addEventListener('click', () => { const action = item.dataset.action; if (this._contextTarget) { this._handleContextAction(action, this._contextTarget); } this._hideContextMenu(); }); }); // 点击画布空白处关闭菜单 this._renderer.domElement.addEventListener('pointerdown', () => { this._hideContextMenu(); }); // 时间轴 const timeline = root.querySelector('#timeline'); if (timeline) { timeline.addEventListener('click', (e) => { const rect = timeline.getBoundingClientRect(); const ratio = (e.clientX - rect.left) / rect.width; const progress = root.querySelector('#timeline-progress'); if (progress) progress.style.width = (ratio * 100) + '%'; this._applyTimelineSnapshot(ratio); }); } } /** 初始化控制面板(placeholder,被 _initUIBindings 替代) */ _initControls() { // 已在 _initUIBindings 中实现 } /** 切换视图模式 */ _switchView(mode) { this._currentView = mode; // 更新按钮状态 this.shadowRoot.querySelectorAll('.view-btn').forEach(btn => { btn.classList.toggle('active', btn.dataset.view === mode); }); // 根据视图模式切换可见性 const layerNames = ['memory', 'knowledge', 'goals', 'skills', 'emotions', 'mirror', 'social']; if (mode === VIEW_MODES.ALL || mode === VIEW_MODES.PANORAMIC) { layerNames.forEach(name => { if (this._layers[name]) this._layers[name].visible = true; }); } else { layerNames.forEach(name => { if (this._layers[name]) { this._layers[name].visible = (name === mode); } }); // 在特定视图中也显示反思之镜 if (this._layers.mirror && mode !== VIEW_MODES.MEMORY) { // 保持镜面可见 } } // 更新可见性开关按钮 this.shadowRoot.querySelectorAll('.toggle-btn').forEach(btn => { const layerName = btn.dataset.layer; if (layerName && this._layers[layerName]) { btn.classList.toggle('on', this._layers[layerName].visible); } }); } /** 切换控制面板显隐 */ _togglePanel() { const panel = this.shadowRoot.querySelector('#control-panel'); const btn = this.shadowRoot.querySelector('#toggle-panel-btn'); if (panel) { panel.classList.toggle('hidden'); } } /** 显示悬浮框 */ _showTooltipFor(userData, event) { const tooltip = this.shadowRoot.querySelector('#tooltip'); const titleEl = this.shadowRoot.querySelector('#tooltip-title'); const contentEl = this.shadowRoot.querySelector('#tooltip-content'); if (!tooltip || !titleEl || !contentEl) return; const rect = this._renderer.domElement.getBoundingClientRect(); let title = ''; let content = ''; switch (userData.type) { case 'memory': { const mem = userData.data; title = mem.title; const sentimentLabel = mem.sentiment > 0.3 ? '积极' : mem.sentiment < -0.3 ? '消极' : '中性'; content = `

${mem.content}

重要性: ${(mem.importance * 100).toFixed(0)}% | 访问: ${mem.accessCount}次

情绪: ${sentimentLabel} (${mem.sentiment.toFixed(2)})

记忆 ${sentimentLabel} `; break; } case 'entity': { const ent = userData.data; title = ent.name; content = `

${ent.description}

类型: ${ent.type} | 连接数: ${ent.connections}

${ent.type} `; break; } case 'goal': { const goal = userData.data; title = goal.title; const stateLabel = { completed: '已完成', active: '进行中', paused: '已暂停', abandoned: '已放弃' }; content = `

状态: ${stateLabel[goal.state] || goal.state}

进度: ${(goal.progress * 100).toFixed(0)}%

子目标: ${goal.children ? goal.children.length : 0}个

${goal.state} `; break; } case 'skill': { const skill = userData.data; title = skill.name; content = `

类型: ${skill.type}

熟练度: ${(skill.proficiency * 100).toFixed(0)}%

${skill.type} `; break; } case 'user': { const user = userData.data; title = user.name; content = `

角色: ${user.role}

亲密度: ${(user.closeness * 100).toFixed(0)}%

${user.role} `; break; } } titleEl.textContent = title; contentEl.innerHTML = content; tooltip.style.left = (event.clientX - rect.left + 15) + 'px'; tooltip.style.top = (event.clientY - rect.top - 10) + 'px'; tooltip.classList.add('visible'); } /** 隐藏悬浮框 */ _hideTooltip() { const tooltip = this.shadowRoot.querySelector('#tooltip'); if (tooltip) tooltip.classList.remove('visible'); } /** 显示右键菜单 */ _showContextMenu(x, y) { const menu = this.shadowRoot.querySelector('#context-menu'); if (!menu) return; menu.style.left = x + 'px'; menu.style.top = y + 'px'; menu.classList.add('visible'); } /** 隐藏右键菜单 */ _hideContextMenu() { const menu = this.shadowRoot.querySelector('#context-menu'); if (menu) menu.classList.remove('visible'); } /** 处理右键菜单动作 */ _handleContextAction(action, userData) { switch (action) { case 'focus': if (userData.object) { this._orbitControls?.focusOn(userData.object.position, 10); } break; case 'highlight': this._highlightSameType(userData.type); break; case 'hide': if (this._layers[userData.layer]) { this._layers[userData.layer].visible = false; } break; case 'isolate': this._isolateType(userData.type); break; case 'details': this._showTooltipFor(userData, { clientX: window.innerWidth / 2, clientY: window.innerHeight / 2 }); break; } } /** 高亮同类元素 */ _highlightSameType(type) { this._interactableObjects.forEach(obj => { if (obj.object && obj.object.material) { if (obj.type === type) { obj.object.material.emissiveIntensity = 1.0; } else { obj.object.material.emissiveIntensity = 0.1; } } }); // 3秒后恢复 setTimeout(() => { this._interactableObjects.forEach(obj => { if (obj.object && obj.object.material) { obj.object.material.emissiveIntensity = 0.5; } }); }, 3000); } /** 隔离特定类型 */ _isolateType(type) { const layerMap = { memory: 'memory', entity: 'knowledge', goal: 'goals', skill: 'skills', user: 'social', }; const targetLayer = layerMap[type]; Object.keys(this._layers).forEach(name => { if (this._layers[name]) { this._layers[name].visible = (name === targetLayer); } }); } /** 高亮特定对象 */ _highlightObject(userData) { if (userData.object && userData.object.material) { userData.object.material.emissiveIntensity = 1.0; } } /** 取消高亮对象 */ _unhighlightObject(userData) { if (userData.object && userData.object.material) { const baseIntensity = userData.data?.proficiency !== undefined ? 0.5 : 0.4; userData.object.material.emissiveIntensity = baseIntensity; } } /** 搜索应用 */ _applySearch() { const query = this._searchQuery; this._interactableObjects.forEach(obj => { if (!obj.object || !obj.object.material) return; if (!query) { obj.object.material.opacity = obj.type === 'entity' ? 0.85 : 0.7; return; } const data = obj.data; let text = ''; switch (obj.type) { case 'memory': text = data.title + ' ' + (data.content || ''); break; case 'entity': text = data.name + ' ' + data.type; break; case 'goal': text = data.title + ' ' + data.state; break; case 'skill': text = data.name + ' ' + data.type; break; case 'user': text = data.name + ' ' + data.role; break; } if (text.toLowerCase().includes(query)) { obj.object.material.opacity = 1.0; obj.object.material.emissiveIntensity = 1.0; } else { obj.object.material.opacity = 0.1; obj.object.material.emissiveIntensity = 0.05; } }); } /** 应用时间轴快照 */ _applyTimelineSnapshot(ratio) { // 时间轴进度反馈(演示效果) const progress = this.shadowRoot.querySelector('#timeline-progress'); if (progress) progress.style.width = (ratio * 100) + '%'; // 根据时间轴位置调整元素的可见性和状态 // 这里模拟历史回放效果 this._data.memories.forEach((mem, i) => { const visible = (i / this._data.memories.length) < ratio; // 通过改变大小来模拟时间流逝 }); } /** 触发目标完成爆炸特效 */ _triggerGoalExplosion(position) { const explosion = new ParticleExplosion(position, 0x00E676, 300, 2.5); this._layers.goals.add(explosion.mesh); this._explosions.push(explosion); } /** 隐藏加载画面 */ _hideLoadingScreen() { const screen = this.shadowRoot.querySelector('#loading-screen'); if (screen) { setTimeout(() => { screen.classList.add('fade-out'); setTimeout(() => screen.remove(), 800); }, 500); } } /** 更新统计数字 */ _updateStats() { const root = this.shadowRoot; const setVal = (id, val) => { const el = root.querySelector(`#${id}`); if (el) el.textContent = val; }; setVal('stat-memories', this._data.memories.length); setVal('stat-entities', this._data.entities.length); setVal('stat-goals', this._data.goals.reduce((sum, g) => sum + 1 + (g.children?.length || 0), 0)); setVal('stat-skills', this._data.skills.length); setVal('stat-connections', this._data.relations.length + this._data.connections.length); } /* ========================================================================= * 资源清理 * ========================================================================= */ /** 销毁所有资源 */ _dispose() { if (this._animationId) { cancelAnimationFrame(this._animationId); } // 清理爆炸特效 this._explosions.forEach(e => e.dispose()); this._explosions = []; // 清理场景 if (this._scene) { this._scene.traverse(obj => { if (obj.geometry) obj.geometry.dispose(); if (obj.material) { if (Array.isArray(obj.material)) { obj.material.forEach(m => m.dispose()); } else { obj.material.dispose(); } } }); } // 清理渲染器 if (this._renderer) { this._renderer.dispose(); } } /* ========================================================================= * 公共 API * ========================================================================= */ /** * 更新记忆数据 * @param {Array} memories - 记忆数据数组 */ updateMemories(memories) { this._data.memories = memories; // 清理旧的 while (this._layers.memory.children.length) { const child = this._layers.memory.children[0]; if (child.geometry) child.geometry.dispose(); if (child.material) child.material.dispose(); this._layers.memory.remove(child); } this._buildMemoryNebula(); this._updateStats(); } /** * 更新知识图谱数据 * @param {Array} entities - 实体数组 * @param {Array} relations - 关系数组 */ updateKnowledgeGraph(entities, relations) { this._data.entities = entities; this._data.relations = relations; // 重新运行力导向布局 this._forceLayout.clear(); entities.forEach(e => this._forceLayout.addNode(e.id, e.position)); relations.forEach(r => this._forceLayout.addEdge(r.source, r.target, r.weight)); for (let i = 0; i < 50; i++) this._forceLayout.step(); const positions = this._forceLayout.getPositions(); entities.forEach(e => { if (positions[e.id]) e.position.copy(positions[e.id]); }); // 重建 while (this._layers.knowledge.children.length) { const child = this._layers.knowledge.children[0]; if (child.geometry) child.geometry.dispose(); if (child.material) child.material.dispose(); this._layers.knowledge.remove(child); } this._buildKnowledgeGraph(); this._updateStats(); } /** * 更新情绪数据 * @param {Array} emotions - 情绪数组 */ updateEmotions(emotions) { this._data.emotions = emotions; while (this._layers.emotions.children.length) { const child = this._layers.emotions.children[0]; if (child.geometry) child.geometry.dispose(); if (child.material) child.material.dispose(); this._layers.emotions.remove(child); } this._buildEmotionParticles(); } /** * 标记目标完成并触发爆炸特效 * @param {string} goalId - 目标ID */ completeGoal(goalId) { const goalMesh = this._layers.goals?.getObjectByName(goalId); if (goalMesh) { this._triggerGoalExplosion(goalMesh.position); goalMesh.material.color.setHex(GOAL_STATE_COLORS.completed); goalMesh.material.emissive.setHex(GOAL_STATE_COLORS.completed); goalMesh.material.opacity = 1.0; } // 更新数据 const findGoal = (goals) => { for (const g of goals) { if (g.id === goalId) return g; if (g.children) { const found = findGoal(g.children); if (found) return found; } } return null; }; const goal = findGoal(this._data.goals); if (goal) { goal.state = 'completed'; goal.progress = 1.0; } } /** * 获取当前视图模式 * @returns {string} */ getViewMode() { return this._currentView; } /** * 切换暂停/播放 * @param {boolean} [paused] - 可选,指定暂停状态 */ togglePause(paused) { this._paused = paused !== undefined ? paused : !this._paused; } /** * 导出当前状态快照 * @returns {Object} 包含所有可视化数据的快照对象 */ exportSnapshot() { return { timestamp: Date.now(), viewMode: this._currentView, memories: this._data.memories.map(m => ({ ...m, position: { x: m.position.x, y: m.position.y, z: m.position.z } })), emotions: [...this._data.emotions], goals: JSON.parse(JSON.stringify(this._data.goals)), }; } } /* ========================================================================= * 注册自定义元素 * ========================================================================= */ if (!customElements.get('consciousness-3d-space')) { customElements.define('consciousness-3d-space', Consciousness3DSpace); } /* ========================================================================= * 导出(兼容 ES Module 和全局引用) * ========================================================================= */ if (typeof module !== 'undefined' && module.exports) { module.exports = { Consciousness3DSpace }; }