create-definedmotion 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/template/src/assets/audio/testing_shadow_glow_song.mp3 +0 -0
- package/template/src/assets/for_tests/svg/gravity_text.svg +38 -0
- package/template/src/assets/for_tests/svg/grip_figure.svg +28 -0
- package/template/src/entry.ts +1 -1
- package/template/src/example_scenes/dependencyScene.ts +2 -4
- package/template/src/example_scenes/fourierSeriesScene.ts +7 -8
- package/template/src/example_scenes/keyboardScene.ts +3 -5
- package/template/src/example_scenes/latex_text_transitions_scene.ts +146 -0
- package/template/src/example_scenes/tests/animations/camera_movements/test_2d_camera_centers_labels.ts +53 -0
- package/template/src/example_scenes/tests/animations/camera_movements/test_2d_camera_hits_markers.ts +40 -0
- package/template/src/example_scenes/tests/animations/camera_movements/test_camera_rotate_quaternion.ts +17 -0
- package/template/src/example_scenes/tests/animations/camera_movements/test_camera_waypoints_sequential.ts +29 -0
- package/template/src/example_scenes/tests/animations/camera_movements/test_fly_camera_waypoints_verifiable.ts +87 -0
- package/template/src/example_scenes/tests/animations/camera_movements/test_zoom_perspective_sequential.ts +17 -0
- package/template/src/example_scenes/tests/animations/latex/test_latex_blue_particle_transition.ts +82 -0
- package/template/src/example_scenes/tests/animations/latex/test_latex_highlight_animation.ts +64 -0
- package/template/src/example_scenes/tests/animations/latex/test_latex_mark_animation.ts +42 -0
- package/template/src/example_scenes/tests/animations/latex/test_latex_particle_transition.ts +48 -0
- package/template/src/example_scenes/tests/animations/latex/test_latex_particle_transition_complex.ts +65 -0
- package/template/src/example_scenes/tests/animations/latex/test_latex_particle_transition_super_complex.ts +86 -0
- package/template/src/example_scenes/tests/animations/latex/test_with_environment_latex_particle_transition.ts +80 -0
- package/template/src/example_scenes/tests/animations/latex/test_write_latex_animation.ts +28 -0
- package/template/src/example_scenes/tests/animations/latex/test_write_latex_animation_2.ts +34 -0
- package/template/src/example_scenes/tests/animations/latex/test_write_latex_animation_3.ts +34 -0
- package/template/src/example_scenes/tests/audio/test_long_audio.ts +11 -0
- package/template/src/example_scenes/tests/audio/test_many_short_sounds.ts +50 -0
- package/template/src/example_scenes/tests/environment/test_hdri_performance.ts +14 -0
- package/template/src/example_scenes/tests/svg/test_basic_latex_query.ts +59 -0
- package/template/src/example_scenes/tests/svg/test_basic_svg.ts +11 -0
- package/template/src/example_scenes/tests/svg/test_colored_latex_to_svg.ts +42 -0
- package/template/src/example_scenes/tests/svg/test_complex_latex_to_svg.ts +22 -0
- package/template/src/example_scenes/tests/svg/test_latex_to_svg.ts +17 -0
- package/template/src/example_scenes/tests/svg/test_material_on_latex.ts +43 -0
- package/template/src/example_scenes/tests/svg/test_query_latex_variables.ts +66 -0
- package/template/src/example_scenes/tests/svg/test_regular_text_latex.ts +21 -0
- package/template/src/example_scenes/tests/svg/test_super_complex_latex_to_svg.ts +98 -0
- package/template/src/example_scenes/tests/svg/test_transition_svgs.ts +33 -0
- package/template/src/example_scenes/tests/svg/test_update_svg_object.ts +19 -0
- package/template/src/example_scenes/tests/svg/test_yellow_grip_symbol_svg.ts +11 -0
- package/template/src/example_scenes/tutorials/medium1.ts +3 -5
- package/template/src/example_scenes/vectorField.ts +2 -4
- package/template/src/example_scenes/visulizingFunctions.ts +3 -5
- package/template/src/main/rendering.ts +38 -21
- package/template/src/renderer/src/App.svelte +40 -12
- package/template/src/renderer/src/lib/animation/animations.ts +141 -88
- package/template/src/renderer/src/lib/animation/captureCanvas.ts +1 -15
- package/template/src/renderer/src/lib/animation/latexMarkAndHighlight.ts +349 -0
- package/template/src/renderer/src/lib/animation/latexTransitionsAndWrite.ts +558 -0
- package/template/src/renderer/src/lib/audio/manager.ts +185 -0
- package/template/src/renderer/src/lib/rendering/hdri.ts +273 -0
- package/template/src/renderer/src/lib/rendering/lighting3d.ts +0 -105
- package/template/src/renderer/src/lib/rendering/setup.ts +7 -1
- package/template/src/renderer/src/lib/rendering/svg/latexSVGQueries.ts +44 -0
- package/template/src/renderer/src/lib/rendering/svg/latexToSVG.ts +132 -0
- package/template/src/renderer/src/lib/rendering/svg/svgObjectHelpers.ts +59 -0
- package/template/src/renderer/src/lib/rendering/svg/svgRendering.ts +120 -0
- package/template/src/renderer/src/lib/scene/sceneClass.ts +93 -31
- package/template/src/renderer/src/lib/audio/loader.ts +0 -104
- package/template/src/renderer/src/lib/rendering/materials.ts +0 -6
- package/template/src/renderer/src/lib/rendering/protocols.ts +0 -21
- package/template/src/renderer/src/lib/rendering/svg/drawing.ts +0 -213
- package/template/src/renderer/src/lib/rendering/svg/parsing.ts +0 -717
- package/template/src/renderer/src/lib/rendering/svg/rastered.ts +0 -42
- package/template/src/renderer/src/lib/rendering/svgObjects.ts +0 -1137
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// test_2d_camera_centers_labels.ts
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import { AnimatedScene, HotReloadSetting, SpaceSetting } from '$renderer/lib/scene/sceneClass'
|
|
4
|
+
import { moveCameraToAnim } from '$renderer/lib/animation/animations'
|
|
5
|
+
|
|
6
|
+
function labeledSquare(text: string, color: string) {
|
|
7
|
+
const g = new THREE.Group()
|
|
8
|
+
const rect = new THREE.Mesh(new THREE.PlaneGeometry(3, 3), new THREE.MeshBasicMaterial({ color }))
|
|
9
|
+
|
|
10
|
+
g.add(rect)
|
|
11
|
+
return g
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const test_2d_camera_centers_labels = (): AnimatedScene =>
|
|
15
|
+
new AnimatedScene(1500, 1500, SpaceSetting.TwoDim, HotReloadSetting.TraceFromStart, async (dm) => {
|
|
16
|
+
// faint grid background
|
|
17
|
+
for (let x = -12; x <= 12; x += 3) {
|
|
18
|
+
const line = new THREE.Mesh(new THREE.PlaneGeometry(0.02, 30), new THREE.MeshBasicMaterial({ color: '#6b7280', transparent: true, opacity: 0.7}))
|
|
19
|
+
line.position.set(x, 0, -0.1); dm.add(line)
|
|
20
|
+
}
|
|
21
|
+
for (let y = -12; y <= 12; y += 3) {
|
|
22
|
+
const line = new THREE.Mesh(new THREE.PlaneGeometry(30, 0.02), new THREE.MeshBasicMaterial({ color: '#6b7280', transparent: true, opacity: 0.7 }))
|
|
23
|
+
line.position.set(0, y, -0.1); dm.add(line)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// center crosshair
|
|
27
|
+
const h = new THREE.Mesh(new THREE.PlaneGeometry(30, 0.03), new THREE.MeshBasicMaterial({ color: '#ffffff' }))
|
|
28
|
+
const v = new THREE.Mesh(new THREE.PlaneGeometry(0.03, 30), new THREE.MeshBasicMaterial({ color: '#ffffff' }))
|
|
29
|
+
dm.add(h, v)
|
|
30
|
+
|
|
31
|
+
// squares at exact grid points
|
|
32
|
+
const S1 = labeledSquare('A', '#f97316'); S1.position.set(-6, 6, 0); dm.add(S1)
|
|
33
|
+
const S2 = labeledSquare('B', '#22c55e'); S2.position.set( 6, 6, 0); dm.add(S2)
|
|
34
|
+
const S3 = labeledSquare('C', '#3b82f6'); S3.position.set( 6, -6, 0); dm.add(S3)
|
|
35
|
+
const S4 = labeledSquare('D', '#ef4444'); S4.position.set(-6, -6, 0); dm.add(S4)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
dm.camera.zoom *= 1.5
|
|
39
|
+
|
|
40
|
+
const z = dm.camera.position.z
|
|
41
|
+
dm.camera.position.set(0, 0, z)
|
|
42
|
+
|
|
43
|
+
const zOffset = new THREE.Vector3(0,0,z)
|
|
44
|
+
|
|
45
|
+
dm.camera.position.copy(S1.position.clone().add(zOffset))
|
|
46
|
+
|
|
47
|
+
// center camera over each square in clockwise order
|
|
48
|
+
dm.addDeferredAnims( moveCameraToAnim(dm.camera, { position: S2.position.clone().add(zOffset) }, 600) )
|
|
49
|
+
dm.addDeferredAnims( moveCameraToAnim(dm.camera, { position: S3.position.clone().add(zOffset) }, 600) )
|
|
50
|
+
dm.addDeferredAnims( moveCameraToAnim(dm.camera, { position: S4.position.clone().add(zOffset) }, 600) )
|
|
51
|
+
dm.addDeferredAnims( moveCameraToAnim(dm.camera, { position: S1.position.clone().add(zOffset) }, 600) )
|
|
52
|
+
|
|
53
|
+
})
|
package/template/src/example_scenes/tests/animations/camera_movements/test_2d_camera_hits_markers.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// test_2d_camera_hits_markers.ts
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import { AnimatedScene, HotReloadSetting, SpaceSetting } from '$renderer/lib/scene/sceneClass'
|
|
4
|
+
import { moveCameraToAnim } from '$renderer/lib/animation/animations'
|
|
5
|
+
|
|
6
|
+
// tiny helper
|
|
7
|
+
const dot = (c: string) => new THREE.Mesh(
|
|
8
|
+
new THREE.CircleGeometry(0.5, 32),
|
|
9
|
+
new THREE.MeshBasicMaterial({ color: c })
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
export const test_2d_camera_hits_markers = (): AnimatedScene =>
|
|
13
|
+
new AnimatedScene(1000, 1000, SpaceSetting.TwoDim, HotReloadSetting.TraceFromStart, async (dm) => {
|
|
14
|
+
// Center crosshair (so we can see when a marker is exactly under the center)
|
|
15
|
+
const horiz = new THREE.Mesh(new THREE.PlaneGeometry(30, 0.1), new THREE.MeshBasicMaterial({ color: '#ffffff' }))
|
|
16
|
+
const vert = new THREE.Mesh(new THREE.PlaneGeometry(0.1, 30), new THREE.MeshBasicMaterial({ color: '#ffffff' }))
|
|
17
|
+
dm.add(horiz, vert)
|
|
18
|
+
|
|
19
|
+
// Markers at precise world coords
|
|
20
|
+
const A = dot('#ef4444'); A.position.set(-8, 6, 0); dm.add(A)
|
|
21
|
+
const B = dot('#3b82f6'); B.position.set( 9, -4, 0); dm.add(B)
|
|
22
|
+
const C = dot('#10b981'); C.position.set( 0, 0, 0); dm.add(C)
|
|
23
|
+
|
|
24
|
+
// Start camera (TwoDim => Orthographic camera with fixed Z; we keep its current Z)
|
|
25
|
+
const z = dm.camera.position.z
|
|
26
|
+
dm.camera.position.set(0, 0, z)
|
|
27
|
+
|
|
28
|
+
// Move center over A, then B, then C — one deferred call per step (sequential)
|
|
29
|
+
dm.addDeferredAnims(
|
|
30
|
+
moveCameraToAnim(dm.camera, { position: new THREE.Vector3(-8, 6, z) }, 700)
|
|
31
|
+
)
|
|
32
|
+
dm.addDeferredAnims(
|
|
33
|
+
moveCameraToAnim(dm.camera, { position: new THREE.Vector3( 9, -4, z) }, 700)
|
|
34
|
+
)
|
|
35
|
+
dm.addDeferredAnims(
|
|
36
|
+
moveCameraToAnim(dm.camera, { position: new THREE.Vector3( 0, 0, z) }, 700)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
dm.addWait(400)
|
|
40
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as THREE from 'three'
|
|
2
|
+
import { AnimatedScene, HotReloadSetting, SpaceSetting } from '$renderer/lib/scene/sceneClass'
|
|
3
|
+
import { rotateCameraToAnim } from '$renderer/lib/animation/animations'
|
|
4
|
+
|
|
5
|
+
export const test_camera_rotate_quaternion = (): AnimatedScene =>
|
|
6
|
+
new AnimatedScene(1000, 800, SpaceSetting.ThreeDim, HotReloadSetting.TraceFromStart, async (dm) => {
|
|
7
|
+
dm.add(new THREE.AxesHelper(6))
|
|
8
|
+
dm.camera.position.set(0, 4, 10)
|
|
9
|
+
|
|
10
|
+
const yawRight = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI/4, 0))
|
|
11
|
+
const pitchDown = new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI/6, 0, 0))
|
|
12
|
+
|
|
13
|
+
dm.addDeferredAnims(rotateCameraToAnim(dm.camera, { rotation: yawRight }, 800))
|
|
14
|
+
dm.addDeferredAnims(rotateCameraToAnim(dm.camera, { rotation: pitchDown }, 800))
|
|
15
|
+
|
|
16
|
+
dm.addWait(300)
|
|
17
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { moveCameraToAnim } from "$renderer/lib/animation/animations";
|
|
2
|
+
import { AnimatedScene, HotReloadSetting, SpaceSetting } from "$renderer/lib/scene/sceneClass";
|
|
3
|
+
import * as THREE from 'three'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export const test_camera_waypoints_sequential = (): AnimatedScene => {
|
|
8
|
+
return new AnimatedScene(1200, 800, SpaceSetting.ThreeDim, HotReloadSetting.TraceFromStart, async (dm) => {
|
|
9
|
+
dm.add(new THREE.GridHelper(40, 40))
|
|
10
|
+
|
|
11
|
+
// Visual markers
|
|
12
|
+
const red = new THREE.Mesh(new THREE.SphereGeometry(1.2), new THREE.MeshBasicMaterial({ color: '#ef4444' }))
|
|
13
|
+
const blue = new THREE.Mesh(new THREE.BoxGeometry(2,2,2), new THREE.MeshBasicMaterial({ color: '#3b82f6' }))
|
|
14
|
+
const green = new THREE.Mesh(new THREE.ConeGeometry(1.2,2,32), new THREE.MeshBasicMaterial({ color: '#10b981' }))
|
|
15
|
+
red.position.set(-8, 0, 0); blue.position.set(8, 0, 0); green.position.set(0, 0, -12)
|
|
16
|
+
dm.add(red, blue, green)
|
|
17
|
+
|
|
18
|
+
// Start camera
|
|
19
|
+
dm.camera.position.set(0, 8, 16)
|
|
20
|
+
dm.camera.lookAt(0, 0, 0)
|
|
21
|
+
|
|
22
|
+
// SEQUENTIAL: one call per addDeferredAnims
|
|
23
|
+
dm.addDeferredAnims(moveCameraToAnim(dm.camera, { position: new THREE.Vector3(-8, 6, 14) }, 900))
|
|
24
|
+
dm.addDeferredAnims(moveCameraToAnim(dm.camera, { position: new THREE.Vector3( 8, 6, 14) }, 900))
|
|
25
|
+
dm.addDeferredAnims(moveCameraToAnim(dm.camera, { position: new THREE.Vector3( 0, 7, 10) }, 900))
|
|
26
|
+
|
|
27
|
+
dm.addWait(400)
|
|
28
|
+
})
|
|
29
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// test_fly_minimal_two_poses.ts
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import { AnimatedScene, HotReloadSetting, SpaceSetting } from '$renderer/lib/scene/sceneClass'
|
|
4
|
+
import { flyCameraToAnim } from '$renderer/lib/animation/animations'
|
|
5
|
+
|
|
6
|
+
// ======================
|
|
7
|
+
// === EDIT HERE ========
|
|
8
|
+
// Marker positions (sphere & cube)
|
|
9
|
+
const SPHERE_POS = new THREE.Vector3(-6, 0, -6)
|
|
10
|
+
const CUBE_POS = new THREE.Vector3( 6, 0, -6)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// Camera pose A (position + quaternion)
|
|
16
|
+
const CAM_A_POS = new THREE.Vector3(-8.478426,
|
|
17
|
+
2.932849,
|
|
18
|
+
-1.628103)
|
|
19
|
+
|
|
20
|
+
// Example: look slightly right & down
|
|
21
|
+
const CAM_A_QUAT = new THREE.Quaternion(-0.2782336,
|
|
22
|
+
-0.2736528,
|
|
23
|
+
-0.08303509,
|
|
24
|
+
0.9169544)
|
|
25
|
+
|
|
26
|
+
// Camera pose B (position + quaternion)
|
|
27
|
+
const CAM_B_POS = new THREE.Vector3( 9.855000,
|
|
28
|
+
2.759370,
|
|
29
|
+
-1.223401)
|
|
30
|
+
// Example: look slightly left & down
|
|
31
|
+
const CAM_B_QUAT = new THREE.Quaternion( -0.2497320,
|
|
32
|
+
0.3230065,
|
|
33
|
+
0.08878684,
|
|
34
|
+
0.9085250)
|
|
35
|
+
// ======================
|
|
36
|
+
|
|
37
|
+
export const test_fly_minimal_two_poses = (): AnimatedScene =>
|
|
38
|
+
new AnimatedScene(1200, 800, SpaceSetting.ThreeDim, HotReloadSetting.TraceFromStart, async (dm) => {
|
|
39
|
+
// Grid floor
|
|
40
|
+
dm.add(new THREE.GridHelper(60, 60))
|
|
41
|
+
|
|
42
|
+
// Sphere marker
|
|
43
|
+
const sphere = new THREE.Mesh(
|
|
44
|
+
new THREE.SphereGeometry(1, 32, 16),
|
|
45
|
+
new THREE.MeshBasicMaterial({ color: '#3b82f6' })
|
|
46
|
+
)
|
|
47
|
+
sphere.position.copy(SPHERE_POS)
|
|
48
|
+
dm.add(sphere)
|
|
49
|
+
|
|
50
|
+
// Cube marker
|
|
51
|
+
const cube = new THREE.Mesh(
|
|
52
|
+
new THREE.BoxGeometry(2, 2, 2),
|
|
53
|
+
new THREE.MeshBasicMaterial({ color: '#ef4444' })
|
|
54
|
+
)
|
|
55
|
+
cube.position.copy(CUBE_POS)
|
|
56
|
+
dm.add(cube)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
const startPos = new THREE.Vector3(0, 6, 18)
|
|
60
|
+
// Start camera (anything reasonable)
|
|
61
|
+
dm.camera.position.copy(startPos)
|
|
62
|
+
dm.camera.lookAt(0, 0, 0)
|
|
63
|
+
|
|
64
|
+
// Leg 1: fly to CAM_A
|
|
65
|
+
dm.addDeferredAnims(
|
|
66
|
+
flyCameraToAnim(dm.camera, { position: CAM_A_POS, rotation: CAM_A_QUAT }, 1000)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
// Small pause to inspect
|
|
70
|
+
dm.addWait(200)
|
|
71
|
+
|
|
72
|
+
// Leg 2: fly to CAM_B
|
|
73
|
+
dm.addDeferredAnims(
|
|
74
|
+
flyCameraToAnim(dm.camera, { position: CAM_B_POS, rotation: CAM_B_QUAT }, 1000)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
dm.addWait(200)
|
|
78
|
+
|
|
79
|
+
const from = startPos.clone()
|
|
80
|
+
const target = new THREE.Vector3(0, 0, 0)
|
|
81
|
+
const m = new THREE.Matrix4().lookAt(from, target, new THREE.Vector3(0, 1, 0))
|
|
82
|
+
const q = new THREE.Quaternion().setFromRotationMatrix(m)
|
|
83
|
+
|
|
84
|
+
dm.addDeferredAnims(
|
|
85
|
+
flyCameraToAnim(dm.camera, { position: startPos, rotation: q}, 1000)
|
|
86
|
+
)
|
|
87
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as THREE from 'three'
|
|
2
|
+
import { AnimatedScene, HotReloadSetting, SpaceSetting } from '$renderer/lib/scene/sceneClass'
|
|
3
|
+
import { zoomCameraToAnim } from '$renderer/lib/animation/animations'
|
|
4
|
+
|
|
5
|
+
export const test_zoom_perspective_sequential = (): AnimatedScene =>
|
|
6
|
+
new AnimatedScene(1000, 700, SpaceSetting.ThreeDim, HotReloadSetting.TraceFromStart, async (dm) => {
|
|
7
|
+
dm.add(new THREE.GridHelper(40, 40))
|
|
8
|
+
dm.camera.position.set(0, 6, 16)
|
|
9
|
+
dm.camera.lookAt(0, 0, 0)
|
|
10
|
+
|
|
11
|
+
const initialFov = (dm.camera as THREE.PerspectiveCamera).fov
|
|
12
|
+
|
|
13
|
+
dm.addDeferredAnims(zoomCameraToAnim(dm.camera, { fov: 30 }, 900))
|
|
14
|
+
dm.addDeferredAnims(zoomCameraToAnim(dm.camera, { fov: initialFov }, 900))
|
|
15
|
+
|
|
16
|
+
dm.addWait(200)
|
|
17
|
+
})
|
package/template/src/example_scenes/tests/animations/latex/test_latex_blue_particle_transition.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// test_latex_particle_transition_blue.ts
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import {
|
|
4
|
+
AnimatedScene,
|
|
5
|
+
HotReloadSetting,
|
|
6
|
+
SpaceSetting
|
|
7
|
+
} from '$renderer/lib/scene/sceneClass'
|
|
8
|
+
import { latexToSVG } from '$renderer/lib/rendering/svg/latexToSVG'
|
|
9
|
+
import { createSVGShape } from '$renderer/lib/rendering/svg/svgRendering'
|
|
10
|
+
import { setOpacity } from '$renderer/lib/animation/animations'
|
|
11
|
+
import { latexParticleTransitionAnim } from '$renderer/lib/animation/latexTransitionsAndWrite'
|
|
12
|
+
|
|
13
|
+
export const test_latex_blue_particle_transition = (): AnimatedScene => {
|
|
14
|
+
return new AnimatedScene(
|
|
15
|
+
1000,
|
|
16
|
+
1000,
|
|
17
|
+
SpaceSetting.ThreeDim,
|
|
18
|
+
HotReloadSetting.TraceFromStart,
|
|
19
|
+
async (dm) => {
|
|
20
|
+
// 1) Two related equations to morph between
|
|
21
|
+
const latexA = String.raw`\nabla \cdot \vec{E} = \frac{\rho}{\varepsilon_0}`
|
|
22
|
+
const latexB = String.raw`\nabla \cdot \vec{D} = \rho_{\mathrm{free}}`
|
|
23
|
+
|
|
24
|
+
// 2) LaTeX → SVG → THREE.Group
|
|
25
|
+
const svgA = latexToSVG(latexA)
|
|
26
|
+
const svgB = latexToSVG(latexB)
|
|
27
|
+
|
|
28
|
+
const groupA = createSVGShape(svgA, 20)
|
|
29
|
+
const groupB = createSVGShape(svgB, 20)
|
|
30
|
+
|
|
31
|
+
// 2.5) Tint both equations blue
|
|
32
|
+
const blue = new THREE.Color('#3b82f6')
|
|
33
|
+
|
|
34
|
+
const tintGroupBlue = (group: THREE.Group) => {
|
|
35
|
+
group.traverse(obj => {
|
|
36
|
+
const mesh = obj as THREE.Mesh
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
if (!mesh.isMesh) return
|
|
39
|
+
const mat = mesh.material
|
|
40
|
+
if (Array.isArray(mat)) {
|
|
41
|
+
mat.forEach(m => {
|
|
42
|
+
const anyMat = m as any
|
|
43
|
+
if (anyMat && anyMat.color && anyMat.color.isColor) {
|
|
44
|
+
anyMat.color.copy(blue)
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
} else {
|
|
48
|
+
const anyMat = mat as any
|
|
49
|
+
if (anyMat && anyMat.color && anyMat.color.isColor) {
|
|
50
|
+
anyMat.color.copy(blue)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
tintGroupBlue(groupA)
|
|
57
|
+
tintGroupBlue(groupB)
|
|
58
|
+
|
|
59
|
+
// 3) Place both at origin
|
|
60
|
+
groupA.position.set(0, 0, 0)
|
|
61
|
+
groupB.position.set(0, 0, 0)
|
|
62
|
+
|
|
63
|
+
// Add to scene
|
|
64
|
+
dm.add(groupA)
|
|
65
|
+
dm.add(groupB)
|
|
66
|
+
|
|
67
|
+
// 4) Make the target equation invisible initially
|
|
68
|
+
setOpacity(groupB, 0)
|
|
69
|
+
|
|
70
|
+
// 5) Simple camera setup so the equations are clearly visible
|
|
71
|
+
dm.camera.position.set(0, 0, 30)
|
|
72
|
+
dm.camera.lookAt(new THREE.Vector3(0, 0, 0))
|
|
73
|
+
|
|
74
|
+
// 6) Add the particle transition animation
|
|
75
|
+
// (particles will pick up the same blue via pickColorFromGroup)
|
|
76
|
+
dm.addDeferredAnims(latexParticleTransitionAnim(groupA, groupB))
|
|
77
|
+
|
|
78
|
+
// Optional pause after the morph
|
|
79
|
+
dm.addWait(300)
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as THREE from 'three'
|
|
2
|
+
import { AnimatedScene, HotReloadSetting, SpaceSetting } from '$renderer/lib/scene/sceneClass'
|
|
3
|
+
import { latexToSVG } from '$renderer/lib/rendering/svg/latexToSVG'
|
|
4
|
+
import { createSVGShape } from '$renderer/lib/rendering/svg/svgRendering'
|
|
5
|
+
import { latexHighlightAnim } from '$renderer/lib/animation/latexMarkAndHighlight'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export const test_latex_highlight_animation = (): AnimatedScene =>
|
|
9
|
+
new AnimatedScene(
|
|
10
|
+
1000,
|
|
11
|
+
1000,
|
|
12
|
+
SpaceSetting.ThreeDim,
|
|
13
|
+
HotReloadSetting.TraceFromStart,
|
|
14
|
+
async (dm) => {
|
|
15
|
+
const latex = latexToSVG(String.raw`
|
|
16
|
+
\ell(\theta)
|
|
17
|
+
= - \sum_{i=1}^{n}
|
|
18
|
+
\Big(
|
|
19
|
+
\dmClass{pos}{y_i \log p_\theta(x_i)}
|
|
20
|
+
+
|
|
21
|
+
\dmClass{neg}{(1 - y_i) \log (1 - p_\theta(x_i))}
|
|
22
|
+
\Big)
|
|
23
|
+
`.trim())
|
|
24
|
+
|
|
25
|
+
const group = createSVGShape(latex, 36)
|
|
26
|
+
dm.add(group)
|
|
27
|
+
|
|
28
|
+
// 1) Highlight positive term
|
|
29
|
+
dm.addDeferredAnims(
|
|
30
|
+
latexHighlightAnim(group, 'pos', {
|
|
31
|
+
durationMs: 1800,
|
|
32
|
+
highlightColor: 0x22c55e,
|
|
33
|
+
pulses: 2,
|
|
34
|
+
minMix: 0.0,
|
|
35
|
+
maxMix: 1.0
|
|
36
|
+
})
|
|
37
|
+
)
|
|
38
|
+
dm.addWait(250)
|
|
39
|
+
|
|
40
|
+
// 2) Highlight negative term
|
|
41
|
+
dm.addDeferredAnims(
|
|
42
|
+
latexHighlightAnim(group, 'neg', {
|
|
43
|
+
durationMs: 1800,
|
|
44
|
+
highlightColor: 0xef4444,
|
|
45
|
+
pulses: 2,
|
|
46
|
+
minMix: 0.0,
|
|
47
|
+
maxMix: 1.0
|
|
48
|
+
})
|
|
49
|
+
)
|
|
50
|
+
dm.addWait(250)
|
|
51
|
+
|
|
52
|
+
// 3) Highlight both together with a stronger pulse
|
|
53
|
+
dm.addDeferredAnims(
|
|
54
|
+
latexHighlightAnim(group, ['pos', 'neg'], {
|
|
55
|
+
durationMs: 1800,
|
|
56
|
+
highlightColor: 0xfacc15,
|
|
57
|
+
pulses: 3,
|
|
58
|
+
minMix: 0.2,
|
|
59
|
+
maxMix: 1.0
|
|
60
|
+
})
|
|
61
|
+
)
|
|
62
|
+
dm.addWait(400)
|
|
63
|
+
}
|
|
64
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// test_latex_mark_animation.ts
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import { AnimatedScene, HotReloadSetting, SpaceSetting } from '$renderer/lib/scene/sceneClass'
|
|
4
|
+
import { latexToSVG } from '$renderer/lib/rendering/svg/latexToSVG'
|
|
5
|
+
import { createSVGShape } from '$renderer/lib/rendering/svg/svgRendering'
|
|
6
|
+
import { latexMarkAnim } from '$renderer/lib/animation/latexMarkAndHighlight'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export const test_latex_mark_animation = (): AnimatedScene =>
|
|
10
|
+
new AnimatedScene(
|
|
11
|
+
1000,
|
|
12
|
+
1000,
|
|
13
|
+
SpaceSetting.ThreeDim,
|
|
14
|
+
HotReloadSetting.TraceFromStart,
|
|
15
|
+
async (dm) => {
|
|
16
|
+
const latex = latexToSVG(String.raw`
|
|
17
|
+
\dmClass{lhs}{\int_0^\infty e^{-x^2}\,\mathrm{d}x}
|
|
18
|
+
= \dmClass{rhs}{\frac{\sqrt{\pi}}{2}}
|
|
19
|
+
`.trim())
|
|
20
|
+
|
|
21
|
+
const group = createSVGShape(latex, 28)
|
|
22
|
+
dm.add(group)
|
|
23
|
+
|
|
24
|
+
// 1) Mark the left-hand side only
|
|
25
|
+
dm.addDeferredAnims(
|
|
26
|
+
latexMarkAnim(group, 'lhs')
|
|
27
|
+
)
|
|
28
|
+
dm.addWait(300)
|
|
29
|
+
|
|
30
|
+
// 2) Mark the right-hand side only
|
|
31
|
+
dm.addDeferredAnims(
|
|
32
|
+
latexMarkAnim(group, 'rhs')
|
|
33
|
+
)
|
|
34
|
+
dm.addWait(300)
|
|
35
|
+
|
|
36
|
+
// 3) Mark both sides together using the multi-class path
|
|
37
|
+
dm.addDeferredAnims(
|
|
38
|
+
latexMarkAnim(group, ['lhs', 'rhs'])
|
|
39
|
+
)
|
|
40
|
+
dm.addWait(400)
|
|
41
|
+
}
|
|
42
|
+
)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import { AnimatedScene, HotReloadSetting, SpaceSetting } from '$renderer/lib/scene/sceneClass'
|
|
4
|
+
import { latexToSVG } from '$renderer/lib/rendering/svg/latexToSVG'
|
|
5
|
+
import { createSVGShape } from '$renderer/lib/rendering/svg/svgRendering'
|
|
6
|
+
import { setOpacity } from '$renderer/lib/animation/animations'
|
|
7
|
+
import { latexParticleTransitionAnim } from '$renderer/lib/animation/latexTransitionsAndWrite' // <- your new helper
|
|
8
|
+
|
|
9
|
+
export const test_latex_particle_transition = (): AnimatedScene => {
|
|
10
|
+
return new AnimatedScene(
|
|
11
|
+
1000,
|
|
12
|
+
1000,
|
|
13
|
+
SpaceSetting.ThreeDim,
|
|
14
|
+
HotReloadSetting.TraceFromStart,
|
|
15
|
+
async (dm) => {
|
|
16
|
+
// 1) Two related equations to morph between
|
|
17
|
+
const latexA = String.raw`\nabla \cdot \vec{E} = \frac{\rho}{\varepsilon_0}`
|
|
18
|
+
const latexB = String.raw`\nabla \cdot \vec{D} = \rho_{\mathrm{free}}`
|
|
19
|
+
|
|
20
|
+
// 2) LaTeX → SVG → THREE.Group
|
|
21
|
+
const svgA = latexToSVG(latexA)
|
|
22
|
+
const svgB = latexToSVG(latexB)
|
|
23
|
+
|
|
24
|
+
const groupA = createSVGShape(svgA, 20) // width ≈ 10 units
|
|
25
|
+
const groupB = createSVGShape(svgB, 20)
|
|
26
|
+
|
|
27
|
+
// Place both at origin
|
|
28
|
+
groupA.position.set(0, 0, 0)
|
|
29
|
+
groupB.position.set(0, 0, 0)
|
|
30
|
+
|
|
31
|
+
// Add to scene
|
|
32
|
+
dm.add(groupA)
|
|
33
|
+
dm.add(groupB)
|
|
34
|
+
|
|
35
|
+
// 3) Make the target equation invisible initially (required by your spec)
|
|
36
|
+
setOpacity(groupB, 0)
|
|
37
|
+
|
|
38
|
+
// 4) Simple camera setup so the equations are clearly visible
|
|
39
|
+
dm.camera.position.set(0, 0, 30)
|
|
40
|
+
dm.camera.lookAt(new THREE.Vector3(0, 0, 0))
|
|
41
|
+
|
|
42
|
+
dm.addDeferredAnims(latexParticleTransitionAnim(groupA, groupB))
|
|
43
|
+
|
|
44
|
+
// Optionally: leave a bit of time after the morph finishes
|
|
45
|
+
dm.addWait(300)
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
}
|
package/template/src/example_scenes/tests/animations/latex/test_latex_particle_transition_complex.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// test_latex_particle_transition_complex.ts
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import {
|
|
4
|
+
AnimatedScene,
|
|
5
|
+
HotReloadSetting,
|
|
6
|
+
SpaceSetting
|
|
7
|
+
} from '$renderer/lib/scene/sceneClass'
|
|
8
|
+
import { latexToSVG } from '$renderer/lib/rendering/svg/latexToSVG'
|
|
9
|
+
import { createSVGShape } from '$renderer/lib/rendering/svg/svgRendering'
|
|
10
|
+
import { setOpacity } from '$renderer/lib/animation/animations'
|
|
11
|
+
import { latexParticleTransitionAnim } from '$renderer/lib/animation/latexTransitionsAndWrite'
|
|
12
|
+
|
|
13
|
+
export const test_latex_particle_transition_complex = (): AnimatedScene => {
|
|
14
|
+
return new AnimatedScene(
|
|
15
|
+
1600,
|
|
16
|
+
1600,
|
|
17
|
+
SpaceSetting.ThreeDim,
|
|
18
|
+
HotReloadSetting.TraceFromStart,
|
|
19
|
+
async (dm) => {
|
|
20
|
+
// 1) Two related, more complex LaTeX expressions
|
|
21
|
+
const latexA = String.raw`
|
|
22
|
+
\oint_{\partial V} \vec{D} \cdot d\vec{A}
|
|
23
|
+
\;=\;
|
|
24
|
+
\int_V \rho_{\mathrm{free}}\, dV
|
|
25
|
+
`
|
|
26
|
+
|
|
27
|
+
const latexB = String.raw`
|
|
28
|
+
\nabla \cdot \vec{D}(\vec{r})
|
|
29
|
+
\;=\;
|
|
30
|
+
\rho_{\mathrm{free}}(\vec{r})
|
|
31
|
+
`
|
|
32
|
+
|
|
33
|
+
// 2) LaTeX → SVG → THREE.Group
|
|
34
|
+
const svgA = latexToSVG(latexA)
|
|
35
|
+
const svgB = latexToSVG(latexB)
|
|
36
|
+
|
|
37
|
+
// Slightly wider target width to give the integral signs room
|
|
38
|
+
const groupA = createSVGShape(svgA, 28)
|
|
39
|
+
const groupB = createSVGShape(svgB, 28)
|
|
40
|
+
|
|
41
|
+
// Place both at origin
|
|
42
|
+
groupA.position.set(0, 0, 0)
|
|
43
|
+
groupB.position.set(0, 0, 0)
|
|
44
|
+
|
|
45
|
+
// Add to scene
|
|
46
|
+
dm.add(groupA)
|
|
47
|
+
dm.add(groupB)
|
|
48
|
+
|
|
49
|
+
// 3) Target expression starts invisible
|
|
50
|
+
setOpacity(groupB, 0)
|
|
51
|
+
|
|
52
|
+
// 4) Camera setup
|
|
53
|
+
dm.camera.position.set(0, 0, 35)
|
|
54
|
+
dm.camera.lookAt(new THREE.Vector3(0, 0, 0))
|
|
55
|
+
|
|
56
|
+
// 5) Particle transition:
|
|
57
|
+
// - 2000 ms duration
|
|
58
|
+
// - default particleCount from helper (tune inside helper if needed)
|
|
59
|
+
dm.addDeferredAnims(latexParticleTransitionAnim(groupA, groupB))
|
|
60
|
+
|
|
61
|
+
// A small pause after the morph
|
|
62
|
+
dm.addWait(400)
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// test_latex_particle_transition_super_complex.ts
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import {
|
|
4
|
+
AnimatedScene,
|
|
5
|
+
HotReloadSetting,
|
|
6
|
+
SpaceSetting
|
|
7
|
+
} from '$renderer/lib/scene/sceneClass'
|
|
8
|
+
import { latexToSVG } from '$renderer/lib/rendering/svg/latexToSVG'
|
|
9
|
+
import { createSVGShape } from '$renderer/lib/rendering/svg/svgRendering'
|
|
10
|
+
import { setOpacity } from '$renderer/lib/animation/animations'
|
|
11
|
+
import { latexParticleTransitionAnim } from '$renderer/lib/animation/latexTransitionsAndWrite'
|
|
12
|
+
|
|
13
|
+
export const test_latex_particle_transition_super_complex = (): AnimatedScene => {
|
|
14
|
+
return new AnimatedScene(
|
|
15
|
+
1600,
|
|
16
|
+
1600,
|
|
17
|
+
SpaceSetting.ThreeDim,
|
|
18
|
+
HotReloadSetting.TraceFromStart,
|
|
19
|
+
async (dm) => {
|
|
20
|
+
// --- 1) Two super duper complex LaTeX expressions ---
|
|
21
|
+
|
|
22
|
+
// A: Full softmax cross-entropy loss with explicit logits
|
|
23
|
+
const latexA = String.raw`
|
|
24
|
+
\begin{aligned}
|
|
25
|
+
\mathcal{L}(\theta)
|
|
26
|
+
&= - \sum_{i=1}^N \log p_\theta(y_i \mid x_i) \\
|
|
27
|
+
&= - \sum_{i=1}^N \log
|
|
28
|
+
\frac{\exp\big(f_\theta(x_i)_{y_i}\big)}
|
|
29
|
+
{\sum_{k=1}^K \exp\big(f_\theta(x_i)_k\big)} \\
|
|
30
|
+
&= - \sum_{i=1}^N
|
|
31
|
+
\left(
|
|
32
|
+
f_\theta(x_i)_{y_i}
|
|
33
|
+
- \log \sum_{k=1}^K \exp\big(f_\theta(x_i)_k\big)
|
|
34
|
+
\right)
|
|
35
|
+
\end{aligned}
|
|
36
|
+
`
|
|
37
|
+
|
|
38
|
+
// B: VI ELBO gradient with regularization and KL term
|
|
39
|
+
const latexB = String.raw`
|
|
40
|
+
\begin{aligned}
|
|
41
|
+
\nabla_\theta \mathcal{L}_{\mathrm{ELBO}}(\theta,\phi)
|
|
42
|
+
&= - \mathbb{E}_{q_\phi(z \mid x)}
|
|
43
|
+
\big[ \nabla_\theta \log p_\theta(x \mid z) \big] \\
|
|
44
|
+
&\quad +\;
|
|
45
|
+
\lambda \,\nabla_\theta \lVert \theta \rVert_2^2 \\
|
|
46
|
+
\mathcal{L}_{\mathrm{ELBO}}(\theta,\phi)
|
|
47
|
+
&= \mathbb{E}_{q_\phi(z \mid x)}
|
|
48
|
+
\big[ \log p_\theta(x \mid z) \big]
|
|
49
|
+
- \mathrm{KL}\!\big(q_\phi(z\mid x)\,\|\,p(z)\big)
|
|
50
|
+
\end{aligned}
|
|
51
|
+
`
|
|
52
|
+
|
|
53
|
+
// --- 2) LaTeX → SVG → THREE.Group ---
|
|
54
|
+
|
|
55
|
+
const svgA = latexToSVG(latexA)
|
|
56
|
+
const svgB = latexToSVG(latexB)
|
|
57
|
+
|
|
58
|
+
// Wider target width to fit the long equations nicely
|
|
59
|
+
const targetWidth = 32
|
|
60
|
+
const groupA = createSVGShape(svgA, targetWidth)
|
|
61
|
+
const groupB = createSVGShape(svgB, targetWidth)
|
|
62
|
+
|
|
63
|
+
// Center them around the origin
|
|
64
|
+
groupA.position.set(0, 0, 0)
|
|
65
|
+
groupB.position.set(0, 0, 0)
|
|
66
|
+
|
|
67
|
+
dm.add(groupA)
|
|
68
|
+
dm.add(groupB)
|
|
69
|
+
|
|
70
|
+
// --- 3) Make target invisible initially ---
|
|
71
|
+
setOpacity(groupB, 0)
|
|
72
|
+
|
|
73
|
+
// --- 4) Camera setup: small offset so everything is nicely framed ---
|
|
74
|
+
dm.camera.position.set(0, 0, 40)
|
|
75
|
+
dm.camera.lookAt(new THREE.Vector3(0, 0, 0))
|
|
76
|
+
|
|
77
|
+
// --- 5) Particle transition ---
|
|
78
|
+
// - 2200 ms duration
|
|
79
|
+
// - particleCount controlled inside helper (default 2000)
|
|
80
|
+
dm.addDeferredAnims(latexParticleTransitionAnim(groupA, groupB))
|
|
81
|
+
|
|
82
|
+
// Leave a short pause when done
|
|
83
|
+
dm.addWait(400)
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
}
|