tahamajs/RR / Docs /visualizer /src /physics /token_animation.js
tahamajs's picture
download
raw
5.69 kB
/**
* physics/token_animation.js
* ===========================
* Main simulation frame loop for instanced token particles and motion trails.
*/
import * as THREE from 'three';
import { VISUAL_CONFIG, EXPERT_HEX_COLORS } from '../constants.js';
import { computeToken3DTrajectory } from './token_trajectory.js';
import { triggerNodePulse } from './node_pulses.js';
const dummy = new THREE.Object3D();
const dummyTrail = new THREE.Object3D();
const expertThreeColors = EXPERT_HEX_COLORS.map(c => new THREE.Color(c));
/**
* Updates all token positions, trail matrices, and color tints for one simulation frame.
* @param {THREE.InstancedMesh} mainMesh - Primary token instanced mesh
* @param {THREE.InstancedMesh} trailMesh - Motion trail instanced mesh
* @param {Array<object>} tokenDataArray - Token state pool
* @param {boolean} isCompressedSide - True if compressed column
* @param {object} context - Execution context { modelKey, paradigm, maxGraphHeight, simulationSpeed, enablePulses, isPlaying, interactableMeshes, activeSelectedSublayerKey }
*/
export function updateTokens(mainMesh, trailMesh, tokenDataArray, isCompressedSide = false, context = {}) {
if (!mainMesh || !context.isPlaying) return;
if (!tokenDataArray || tokenDataArray.length === 0) return;
const {
modelKey = 'distilbert',
paradigm = 'svd',
maxGraphHeight = 16.0,
simulationSpeed = 1.0,
enablePulses = true,
interactableMeshes = [],
activeSelectedSublayerKey = null
} = context;
const baseOffsetX = isCompressedSide ? VISUAL_CONFIG.LAYOUT.compressedX : VISUAL_CONFIG.LAYOUT.baselineX;
const defaultColor = isCompressedSide ? new THREE.Color(0x2dd4bf) : new THREE.Color(0x38bdf8);
const residualColor = new THREE.Color(0x60a5fa);
const highlightColor = new THREE.Color(0xffffff);
const count = tokenDataArray.length;
for (let i = 0; i < count; i++) {
const t = tokenDataArray[i];
// 1. Advance vertical progress
t.y += t.speed * simulationSpeed;
if (t.y > maxGraphHeight) {
t.y = 0.2;
t.lateralNoise = (Math.random() - 0.5) * VISUAL_CONFIG.TOKENS.lateralNoiseRange;
}
// 2. Compute 3D position
const curPos = computeToken3DTrajectory(t, t.y, isCompressedSide, modelKey, paradigm, baseOffsetX);
const prevY = Math.max(0.1, t.y - t.speed * simulationSpeed * VISUAL_CONFIG.TOKENS.trailMultiplier);
const prevPos = computeToken3DTrajectory(t, prevY, isCompressedSide, modelKey, paradigm, baseOffsetX);
// 3. Selection highlight check
const isSelectedSublayer = activeSelectedSublayerKey && curPos.sublayer &&
(activeSelectedSublayerKey.includes(curPos.sublayer) || curPos.sublayer.includes(activeSelectedSublayerKey));
// 4. Update Token Mesh Matrix
dummy.position.set(curPos.x, t.y, curPos.z);
let scalePulse = 1.0 + Math.sin(t.y * 3.0 + t.pulsePhase) * 0.15;
if (isSelectedSublayer) {
scalePulse *= 2.2;
}
dummy.scale.set(scalePulse, scalePulse, scalePulse);
dummy.updateMatrix();
mainMesh.setMatrixAt(i, dummy.matrix);
// 5. Update Motion Trail Mesh Matrix
dummyTrail.position.set(prevPos.x, prevY, prevPos.z);
const trailScale = isSelectedSublayer ? 1.4 : VISUAL_CONFIG.TOKENS.trailScale;
dummyTrail.scale.set(trailScale, trailScale, trailScale);
dummyTrail.updateMatrix();
if (trailMesh) trailMesh.setMatrixAt(i, dummyTrail.matrix);
// 6. Token Color Tinting
if (mainMesh.instanceColor) {
if (isSelectedSublayer) {
mainMesh.setColorAt(i, highlightColor);
} else if (t.isResidual) {
mainMesh.setColorAt(i, residualColor);
} else if (isCompressedSide && modelKey === 'qwen') {
if (curPos.sublayer === 'q_proj') mainMesh.setColorAt(i, new THREE.Color(0x38bdf8));
else if (curPos.sublayer === 'k_proj' || curPos.sublayer === 'v_proj') mainMesh.setColorAt(i, new THREE.Color(0xf59e0b));
else if (curPos.sublayer === 'gate_proj') mainMesh.setColorAt(i, new THREE.Color(0xa855f7));
else if (curPos.sublayer === 'up_proj') mainMesh.setColorAt(i, new THREE.Color(0x8b5cf6));
else mainMesh.setColorAt(i, defaultColor);
} else if (isCompressedSide && paradigm === 'moe') {
mainMesh.setColorAt(i, expertThreeColors[t.expertTarget || 0]);
} else {
mainMesh.setColorAt(i, defaultColor);
}
}
// 7. Node pulse trigger
if (enablePulses && interactableMeshes.length > 0) {
const meshCount = interactableMeshes.length;
for (let mIdx = 0; mIdx < meshCount; mIdx++) {
const mesh = interactableMeshes[mIdx];
if (mesh.userData && mesh.userData.isMacro) continue;
const matchesSide = isCompressedSide ? (mesh.position.x > 0) : (mesh.position.x < 0);
if (matchesSide) {
const dx = Math.abs(mesh.position.x - curPos.x);
const dy = Math.abs(mesh.position.y - t.y);
if (dx < (mesh.geometry.parameters?.width || 1.0) / 2 && dy < 0.25) {
triggerNodePulse(mesh);
break;
}
}
}
}
}
mainMesh.instanceMatrix.needsUpdate = true;
if (mainMesh.instanceColor) mainMesh.instanceColor.needsUpdate = true;
if (trailMesh) trailMesh.instanceMatrix.needsUpdate = true;
}

Xet Storage Details

Size:
5.69 kB
·
Xet hash:
a305d71cfa1623b6b9019ad92159185f2a0a51d08718d07af1db06c0b2b98aa8

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.