aboutsummaryrefslogtreecommitdiff
path: root/src/scene/primitives.ts
diff options
context:
space:
mode:
authorLalleSX2026-10-24 14:18:00 +0200
committerLalleSX2026-10-24 14:18:00 +0200
commit389fb3a592832092835da0c2cc1608a57ba5f629 (patch)
treead1f89333ec3c84b906fb6546cee7824f58236fa /src/scene/primitives.ts
parentinit (diff)
download3D-Electrophysics-389fb3a592832092835da0c2cc1608a57ba5f629.tar.gz
3D-Electrophysics-389fb3a592832092835da0c2cc1608a57ba5f629.zip
Add tests for math rendering and interactive scenes; update navigation and viewport handling
- Updated `lab.spec.ts` to navigate directly to the field lesson. - Created `math.spec.ts` with tests for math rendering, error checking, and responsive design. - Added `test4.spec.ts` for interactive scenes, ensuring all questions are functional and accessible. - Modified `vite.config.ts` to keep original question/answer links navigable in production.
Diffstat (limited to '')
-rw-r--r--src/scene/primitives.ts21
1 files changed, 19 insertions, 2 deletions
diff --git a/src/scene/primitives.ts b/src/scene/primitives.ts
index bce9113..384ea1d 100644
--- a/src/scene/primitives.ts
+++ b/src/scene/primitives.ts
@@ -1,4 +1,6 @@
import * as THREE from 'three';
+import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
+import { renderProse } from '../math';
import type { Point } from '../physics/electricField';
export const colours = { positive: '#ff967b', negative: '#73d7ff', field: '#91e2cb', gold: '#f5d58b', muted: '#8294a8' };
@@ -25,7 +27,20 @@ export function arrow(group: THREE.Group, origin: Point, direction: Point, lengt
if (dir.lengthSq() < 1e-24) return;
group.add(new THREE.ArrowHelper(dir.normalize(), vector(origin), length, colour, Math.min(0.16, length * 0.3), Math.min(0.1, length * 0.2)));
}
-export function label(group: THREE.Group, text: string, position: Point, colour: string = '#dbe7f0', width = 2): THREE.Sprite {
+export function label(group: THREE.Group, text: string, position: Point, colour: string = '#dbe7f0', width = 2, minViewportWidth = 0): THREE.Sprite | CSS2DObject {
+ if (text.includes('$')) {
+ const element = document.createElement('div');
+ element.className = 'scene-math-label';
+ element.style.color = colour;
+ renderProse(element, text);
+ const annotation = new CSS2DObject(element);
+ annotation.position.copy(vector(position));
+ annotation.onBeforeRender = () => {
+ element.style.visibility = (element.parentElement?.clientWidth ?? Infinity) < minViewportWidth ? 'hidden' : 'visible';
+ };
+ group.add(annotation);
+ return annotation;
+ }
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d')!;
context.font = '500 44px system-ui, sans-serif';
@@ -52,7 +67,9 @@ export function label(group: THREE.Group, text: string, position: Point, colour:
if (!(camera instanceof THREE.PerspectiveCamera)) return;
sprite.getWorldPosition(cameraPosition).applyMatrix4(camera.matrixWorldInverse);
renderer.getSize(viewportSize);
- const worldHeight = 2 * Math.abs(cameraPosition.z) * Math.tan(THREE.MathUtils.degToRad(camera.getEffectiveFOV()) / 2) * screenHeight / Math.max(1, viewportSize.y);
+ sprite.material.opacity = viewportSize.x < minViewportWidth ? 0 : 1;
+ const responsiveHeight = viewportSize.x < 600 ? screenHeight * 0.78 : screenHeight;
+ const worldHeight = 2 * Math.abs(cameraPosition.z) * Math.tan(THREE.MathUtils.degToRad(camera.getEffectiveFOV()) / 2) * responsiveHeight / Math.max(1, viewportSize.y);
sprite.scale.set(worldHeight * aspect, worldHeight, 1);
sprite.updateMatrixWorld();
};