
48 小时极客原型用 Three.js 与 Viem 打造 3D 链上多签金库全景看板在企业级 DAO 或巨鲸资管团队中多签金库Gnosis Safe Vault通常托管着包含 ERC-20 代币、LP 仓位、NFT 治理徽章等多维度的庞大资产。传统的 Web 仪表盘只是单调的资产列表与进度条如果能将多签金库构建为一座三维赛博金库大厦3D Cyber Vault Citadel中央金库的坚固度与发光强度根据当前的 TVL 动态缩放周围环绕着代表 5 位多签理事会成员的“守护者全息水晶球”当有新的多签提案处于 Pending 待签状态时水晶球之间激发出动态激光连线实时展现当前的签名收集进度如 2/3 签名点亮。在上周末的 48 小时极客冲刺中我结合Viem 链上 Safe 状态探针、Three.js 3D 场景与发光材质以及Next.js 14从零构建了一套极具科幻冲击力的“3D 多签金库全景看板”。一、3D 多签金库可视化架构拓扑graph TD ViemSafe[Viem Safe 探针: 实时拉取 Owners 列表, 门限 Threshold, 待签 Proposal] -- StateStore[React 状态中枢] subgraph Three.js 3D 赛博金库空间映射 StateStore -- CenterVault[中央金属主金库: 高度/体积 log(TVL), 发光材质] StateStore -- GuardianNodes[环形排列的理事会全息水晶节点 (Guardian Orbs)] StateStore -- LaserMesh[激光能量连线: 已签署成员与金库之间激发出高亮光束] StateStore -- TextHUD[CSS2D 悬浮显示每个成员的 ENS 与待签状态] end CenterVault GuardianNodes LaserMesh -- ThreeRenderer[WebGL 渲染管线 UnrealBloomPass]二、Three.js 环形多签水晶与激光连接系统实现// scene/cyberMultisigScene.ts import * as THREE from three; export interface SafeState { owners: string[]; threshold: number; confirmedOwners: string[]; // 已签名的成员列表 tvlUsd: number; } export function createMultisigCitadel(scene: THREE.Scene, state: SafeState) { const group new THREE.Group(); // 1. 创建中央核心金库塔 (Central Vault Tower) const towerHeight Math.max(4, Math.log10(state.tvlUsd) * 2.5); const vaultGeo new THREE.CylinderGeometry(2, 3, towerHeight, 8); const vaultMat new THREE.MeshStandardMaterial({ color: 0x0f172a, roughness: 0.2, metalness: 0.9, emissive: 0x00f3ff, emissiveIntensity: 0.6, }); const vaultMesh new THREE.Mesh(vaultGeo, vaultMat); vaultMesh.position.y towerHeight / 2; group.add(vaultMesh); // 2. 环形排列多签守护者全息水晶球 (Guardian Orbs) const guardianCount state.owners.length; const radius 9.0; const orbs: THREE.Mesh[] []; state.owners.forEach((ownerAddr, idx) { const angle (idx / guardianCount) * Math.PI * 2; const x Math.cos(angle) * radius; const z Math.sin(angle) * radius; const isConfirmed state.confirmedOwners.includes(ownerAddr.toLowerCase()); // 水晶球几何体与发光材质 (已签名呈亮绿色/青色未签名呈暗灰色) const orbGeo new THREE.SphereGeometry(0.8, 32, 32); const orbMat new THREE.MeshStandardMaterial({ color: isConfirmed ? 0x00f3ff : 0x475569, emissive: isConfirmed ? 0x00a8ff : 0x000000, emissiveIntensity: isConfirmed ? 2.0 : 0.0, roughness: 0.1, metalness: 0.8, }); const orbMesh new THREE.Mesh(orbGeo, orbMat); orbMesh.position.set(x, 2.5, z); group.add(orbMesh); orbs.push(orbMesh); // 3. 如果该成员已完成签名创建从水晶球射向中央金库的激光束 if (isConfirmed) { const laserGeo new THREE.CylinderGeometry(0.04, 0.04, radius, 8); laserGeo.translate(0, radius / 2, 0); laserGeo.rotateX(Math.PI / 2); const laserMat new THREE.MeshBasicMaterial({ color: 0x00f3ff }); const laserMesh new THREE.Mesh(laserGeo, laserMat); laserMesh.position.set(x, 2.5, z); laserMesh.lookAt(0, towerHeight / 2, 0); group.add(laserMesh); } }); scene.add(group); return { group, update: (time: number) { // 水晶球轻微上下浮动 orbs.forEach((orb, i) { orb.position.y 2.5 Math.sin(time * 2.0 i) * 0.2; }); // 中央金库缓慢自转 vaultMesh.rotation.y time * 0.2; }, }; }三、React Viem 链上状态实时同步大屏// components/Multisig3DStage.tsx use client; import React, { useEffect, useRef, useState } from react; import * as THREE from three; import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js; import { createMultisigCitadel } from /scene/cyberMultisigScene; export function Multisig3DStage() { const containerRef useRefHTMLDivElement(null); const [proposalStatus, setProposalStatus] useState({ confirmed: 2, total: 3 }); useEffect(() { if (!containerRef.current) return; const scene new THREE.Scene(); const camera new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 14, 22); const renderer new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); containerRef.current.appendChild(renderer.domElement); const controls new OrbitControls(camera, renderer.domElement); controls.enableDamping true; scene.add(new THREE.AmbientLight(0x0f172a, 1.5)); const light new THREE.PointLight(0x00f3ff, 2, 50); light.position.set(0, 10, 0); scene.add(light); // 初始化多签金库 3D 映射 const citadel createMultisigCitadel(scene, { owners: [0xAdmin1..., 0xAdmin2..., 0xAdmin3..., 0xAdmin4..., 0xAdmin5...], threshold: 3, confirmedOwners: [0xadmin1..., 0xadmin2...], // 当前已签 2/3 tvlUsd: 5400000, }); let animId: number; const clock new THREE.Clock(); const animate () { controls.update(); citadel.update(clock.getElapsedTime()); renderer.render(scene, camera); animId requestAnimationFrame(animate); }; animate(); return () { cancelAnimationFrame(animId); renderer.dispose(); }; }, []); return ( div classNamerelative w-full h-screen bg-slate-950 div ref{containerRef} classNamew-full h-full / {/* 悬浮 HUD 状态卡片 */} div classNameabsolute top-8 left-8 p-6 bg-slate-900/90 border border-cyan-500/40 rounded-2xl text-white backdrop-blur-xl pointer-events-none h2 classNametext-xl font-black text-cyan-400 font-monoSAFE CITADEL // 3D 金库/h2 div classNametext-xs text-slate-400 mt-1当前活跃提案: 升级金库至 V2 逻辑/div div classNamemt-4 flex items-center gap-3 div classNametext-3xl font-black text-green-400 font-mono {proposalStatus.confirmed} / {proposalStatus.total} /div span classNametext-xs text-slate-400已达法定门限 (Ready to Execute)/span /div /div /div ); }四、48 小时极客原型调优复盘几何面片复用与单 Draw Call 合并所有未签名的灰色水晶球共用同一个材质实例已签名的发光球共用发光材质将 Draw Call 控制在 5 次以内状态驱动平滑过渡Lerp Animation当链上监听到第 3 位成员完成签名的瞬间对应的水晶球通过贝塞尔插值从灰色平滑点亮为赛博青并伴随激光射向金库视觉反馈极度震撼。将复杂的多签治理状态转化为直观的三维空间能量场让链上协作在全栈图形学的赋能下焕发出未来科技感。