llm-semantic-visualizer / tests /webgl.test.js
hbauzan's picture
feat(nav): lock default camera pose and gate CAM POSE overlay
4232993
Raw
History Blame Contribute Delete
2.7 kB
import { describe, it, expect } from 'vitest';
import * as THREE from 'three';
import { LayoutEngine } from '../src/visualizer/LayoutEngine.js';
import { PointShader } from '../src/engine/Shaders.js';
import { MeshFactory } from '../src/visualizer/MeshFactory.js';
import { Navigation } from '../src/engine/Navigation.js';
describe('WebGL 3D Engine & Spatial Math', () => {
it('LayoutEngine maps 1D embedding vector into 3D space correctly', () => {
const layout = new LayoutEngine({ scaleX: 1.0, scaleY: 100.0, scaleZ: 10.0 });
const rawVector = [0.1, 0.5, -0.2];
const points = layout.mapVectorTo3DPoints(rawVector, 1);
expect(points.length).toBe(3);
expect(points[0]).toBeInstanceOf(THREE.Vector3);
expect(points[1].y).toBeCloseTo(50.0);
expect(points[0].z).toBe(10.0);
});
it('PointShader defines valid vertex and fragment shader GLSL sources', () => {
expect(PointShader.vertexShader).toContain('attribute float aActivation');
expect(PointShader.fragmentShader).toContain('gl_FragColor');
expect(PointShader.fragmentShader).toContain('smoothstep');
});
it('MeshFactory enforces Invariant 3: frustumCulled = false on point cloud mesh', () => {
const testPointsData = [
{ position: new THREE.Vector3(0, 10, 0), activation: 0.8, size: 14.0 },
{ position: new THREE.Vector3(5, 20, 5), activation: 0.3, size: 10.0 }
];
const pointsMesh = MeshFactory.createPointsMesh(testPointsData);
expect(pointsMesh).toBeInstanceOf(THREE.Points);
expect(pointsMesh.frustumCulled).toBe(false);
});
it('Navigation bounds movement velocity smoothly without exponential buildup', () => {
const camera = new THREE.PerspectiveCamera();
camera.position.set(0, 0, 0);
const nav = new Navigation(camera);
nav.keys.KeyW = true;
// Simulate 60 frames holding W
for (let i = 0; i < 60; i++) {
nav.update(0.016);
}
// Velocity should be smoothly bounded around target speed per frame (~0.64), not 8x buildup
expect(nav.velocity.length()).toBeLessThan(2.0);
});
it('Navigation setNavigationView restores the captured default corridor pose', () => {
const camera = new THREE.PerspectiveCamera();
const nav = new Navigation(camera);
nav.setNavigationView();
expect(camera.position.x).toBeCloseTo(-178.3, 1);
expect(camera.position.y).toBeCloseTo(13.5, 1);
expect(camera.position.z).toBeCloseTo(52.2, 1);
const deg2rad = Math.PI / 180;
expect(nav.euler.x).toBeCloseTo(-5.4 * deg2rad, 3);
expect(nav.euler.y).toBeCloseTo(-51.5 * deg2rad, 3);
expect(nav.euler.z).toBeCloseTo(0, 3);
expect(nav.velocity.length()).toBe(0);
});
});