From d834128f2e0c9d93ceaac956e2881c27dbe9dc06 Mon Sep 17 00:00:00 2001 From: Drew C Youngren Date: Tue, 2 Sep 2025 22:43:43 -0400 Subject: [PATCH 1/3] Fix endpoint for sliders --- media/src/objects/Curve.svelte | 2 +- media/src/objects/Function.svelte | 19 +++++++++---------- media/src/objects/Point.svelte | 2 +- media/src/objects/Surface.svelte | 2 +- media/src/objects/Vector.svelte | 2 +- media/src/stories/FluxIntegral.svelte | 2 +- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/media/src/objects/Curve.svelte b/media/src/objects/Curve.svelte index 914c341f..ee817bdf 100644 --- a/media/src/objects/Curve.svelte +++ b/media/src/objects/Curve.svelte @@ -171,7 +171,7 @@ } else { tau += dt / (B - A); } - tau %= 1; + if (tau > 1) tau %= 1; // const T = A + (B - A) * tau; // uncomment this if we want aVal to be animated: diff --git a/media/src/objects/Function.svelte b/media/src/objects/Function.svelte index f201443c..c5b00c50 100644 --- a/media/src/objects/Function.svelte +++ b/media/src/objects/Function.svelte @@ -609,7 +609,7 @@ const update = function (dt) { tau += dt / (t1 - t0); - tau %= 1; + if (tau > 1) tau %= 1; evolveSurface(tVal); @@ -799,26 +799,25 @@ boxMesh.add(boxMeshEdges); const updateBoxes = function () { - const { a, b, c, d} = params; + const { a, b, c, d } = params; try { - [ + [ math.evaluate(a), math.evaluate(b), math.evaluate(c), math.evaluate(d), ]; } catch (e) { - console.error("Can't show integral boxes on nonconstant bounds",e); + console.error("Can't show integral boxes on nonconstant bounds", e); return; } const [A, B, C, D] = [ - math.evaluate(a), - math.evaluate(b), - math.evaluate(c), - math.evaluate(d), - ]; - + math.evaluate(a), + math.evaluate(b), + math.evaluate(c), + math.evaluate(d), + ]; // const t = T0 + tau * (T1 - T0); diff --git a/media/src/objects/Point.svelte b/media/src/objects/Point.svelte index d68a187e..8071917b 100644 --- a/media/src/objects/Point.svelte +++ b/media/src/objects/Point.svelte @@ -215,7 +215,7 @@ const update = (dt = 0) => { tau += dt / (t1 - t0); - tau %= 1; + if (tau > 1) tau %= 1; updatePoint(tVal); }; // Start animating if animation changes (e.g. animating scene published) diff --git a/media/src/objects/Surface.svelte b/media/src/objects/Surface.svelte index 56f52132..f86c485f 100644 --- a/media/src/objects/Surface.svelte +++ b/media/src/objects/Surface.svelte @@ -590,7 +590,7 @@ const update = function (dt = 0) { tau += dt / (t1 - t0); - tau %= 1; + if (tau > 1) tau %= 1; if (isDynamic) evolveSurface(tVal); if (isRhoDynamic) { diff --git a/media/src/objects/Vector.svelte b/media/src/objects/Vector.svelte index 5b38c29b..675f451d 100644 --- a/media/src/objects/Vector.svelte +++ b/media/src/objects/Vector.svelte @@ -256,7 +256,7 @@ const B = math.parse(t1).evaluate(); tau += dt / (B - A); - tau %= 1; + if (tau > 1) tau %= 1; updateVector(tVal); }; diff --git a/media/src/stories/FluxIntegral.svelte b/media/src/stories/FluxIntegral.svelte index e93b29fa..e496573a 100644 --- a/media/src/stories/FluxIntegral.svelte +++ b/media/src/stories/FluxIntegral.svelte @@ -46,7 +46,7 @@ // const currentTime = $tickTock; last = last || $tickTock; tau += $tickTock - last; - tau %= 1; + if (tau > 1) tau %= 1; updateTau(tau); last = $tickTock; } From 5bfb9dc43db02b85e6500c567b4b87bcffc3bf7f Mon Sep 17 00:00:00 2001 From: Drew C Youngren Date: Thu, 4 Sep 2025 06:47:37 -0400 Subject: [PATCH 2/3] Add play mode --- media/src/form-components/PlayButtons.svelte | 14 ++++++++ media/src/objects/Point.svelte | 37 ++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/media/src/form-components/PlayButtons.svelte b/media/src/form-components/PlayButtons.svelte index 13845593..c9fb4b23 100644 --- a/media/src/form-components/PlayButtons.svelte +++ b/media/src/form-components/PlayButtons.svelte @@ -5,6 +5,8 @@ play = () => {}, pause, rew, + clicker = () => {}, + playMode = 'loop', // animate, } = $props(); @@ -32,6 +34,15 @@ + diff --git a/media/src/objects/Point.svelte b/media/src/objects/Point.svelte index 8071917b..965819d1 100644 --- a/media/src/objects/Point.svelte +++ b/media/src/objects/Point.svelte @@ -45,6 +45,7 @@ selectObject, animate, onClose = () => {}, + playMode = 'bounce', } = $props(); let tau = $state(0); @@ -106,6 +107,20 @@ let isDynamic = $derived(dependsOn(params, 't')); let isDiscrete = $derived(dependsOn(params, 'n')); + /** + * @type "once"|"loop"|"bounce" + */ + // let playMode = $state('loop'); + function playModeCycle() { + if (playMode == 'once') { + playMode = 'loop'; + } else if (playMode == 'loop') { + playMode = 'bounce'; + } else { + playMode = 'once'; + } + } + $effect(() => { params; updatePoint(); @@ -213,9 +228,25 @@ // texString1 = `t = ${Math.round(100 * T) / 100}`; + let modeSign = 1; + const update = (dt = 0) => { - tau += dt / (t1 - t0); - if (tau > 1) tau %= 1; + tau += (modeSign * dt) / (t1 - t0); + if (tau > 1) { + if (playMode == 'loop') { + tau %= 1; + } else if (playMode == 'once') { + tau = 1; + animation = false; + } else { + modeSign = -1; + tau = 2 - tau; + } + } + if (tau <= 0) { + modeSign = 1; + tau *= -1; + } updatePoint(tVal); }; // Start animating if animation changes (e.g. animating scene published) @@ -308,6 +339,8 @@ tau = 0; update(); }} + {playMode} + clicker={playModeCycle} /> {/if} From dbae577035ea6a532dd505cf2e4cc52342712c3c Mon Sep 17 00:00:00 2001 From: Drew C Youngren Date: Mon, 15 Sep 2025 18:36:34 -0400 Subject: [PATCH 3/3] Add bounce/loop/once button --- media/src/form-components/PlayButtons.svelte | 6 +++- media/src/objects/Curve.svelte | 38 +++++++++++++++++--- media/src/objects/Function.svelte | 33 +++++++++++++++-- media/src/objects/Point.svelte | 6 +--- media/src/objects/Surface.svelte | 34 ++++++++++++++++-- media/src/objects/Vector.svelte | 37 +++++++++++++++---- 6 files changed, 134 insertions(+), 20 deletions(-) diff --git a/media/src/form-components/PlayButtons.svelte b/media/src/form-components/PlayButtons.svelte index c9fb4b23..aab32d82 100644 --- a/media/src/form-components/PlayButtons.svelte +++ b/media/src/form-components/PlayButtons.svelte @@ -55,6 +55,10 @@ color: white; } .modebtn { - width: 1rem; + width: 3em; /* or px if you prefer */ + text-align: center; } + /* .modebtn:hover { + border: 1px solid white; + } */ diff --git a/media/src/objects/Curve.svelte b/media/src/objects/Curve.svelte index ee817bdf..7c79718a 100644 --- a/media/src/objects/Curve.svelte +++ b/media/src/objects/Curve.svelte @@ -44,6 +44,7 @@ camera, gridStep, selected = $bindable(false), + playMode = 'loop', } = $props(); title = title || `Curve ${++titleIndex}`; @@ -163,15 +164,42 @@ let last; + function playModeCycle() { + if (playMode == 'once') { + playMode = 'loop'; + } else if (playMode == 'loop') { + playMode = 'bounce'; + } else { + playMode = 'once'; + } + } + + let modeSign = 1; + const update = (dt = 0) => { - const { a, b } = params; + // const { a, b } = params; if (vizOptions.TNB) { - tau += dt / arrows.v.speed / (B - A); + tau += (modeSign * dt) / arrows.v.speed / (B - A); } else { - tau += dt / (B - A); + tau += (modeSign * dt) / (B - A); } - if (tau > 1) tau %= 1; + if (tau > 1) { + if (playMode == 'loop') { + tau %= 1; + } else if (playMode == 'once') { + tau = 1; + animation = false; + } else { + modeSign = -1; + tau = 2 - tau; + } + } + if (tau <= 0) { + modeSign = 1; + tau *= -1; + } + // const T = A + (B - A) * tau; // uncomment this if we want aVal to be animated: @@ -663,6 +691,8 @@ animation = false; update(); }} + {playMode} + clicker={playModeCycle} /> {#if isDynamic} diff --git a/media/src/objects/Function.svelte b/media/src/objects/Function.svelte index c5b00c50..5411f6e9 100644 --- a/media/src/objects/Function.svelte +++ b/media/src/objects/Function.svelte @@ -67,6 +67,7 @@ animate, camera, onClose = () => {}, + playMode = 'loop', } = $props(); // $inspect(camera); @@ -577,6 +578,16 @@ */ let isDynamic = $derived(dependsOn(params, 't')); + function playModeCycle() { + if (playMode == 'once') { + playMode = 'loop'; + } else if (playMode == 'loop') { + playMode = 'bounce'; + } else { + playMode = 'once'; + } + } + $effect(() => { [params.z, params.a, params.b, params.c, params.d]; untrack(updateSurface); @@ -607,9 +618,25 @@ if (selected) untrack(flash); }); + let modeSign = 1; + const update = function (dt) { - tau += dt / (t1 - t0); - if (tau > 1) tau %= 1; + tau += (modeSign * dt) / (t1 - t0); + if (tau > 1) { + if (playMode == 'loop') { + tau %= 1; + } else if (playMode == 'once') { + tau = 1; + animation = false; + } else { + modeSign = -1; + tau = 2 - tau; + } + } + if (tau <= 0) { + modeSign = 1; + tau *= -1; + } evolveSurface(tVal); @@ -1180,6 +1207,8 @@ evolveSurface(tVal); render(); }} + {playMode} + clicker={playModeCycle} /> {/if} diff --git a/media/src/objects/Point.svelte b/media/src/objects/Point.svelte index 965819d1..5d81d0db 100644 --- a/media/src/objects/Point.svelte +++ b/media/src/objects/Point.svelte @@ -45,7 +45,7 @@ selectObject, animate, onClose = () => {}, - playMode = 'bounce', + playMode = 'loop', } = $props(); let tau = $state(0); @@ -107,10 +107,6 @@ let isDynamic = $derived(dependsOn(params, 't')); let isDiscrete = $derived(dependsOn(params, 'n')); - /** - * @type "once"|"loop"|"bounce" - */ - // let playMode = $state('loop'); function playModeCycle() { if (playMode == 'once') { playMode = 'loop'; diff --git a/media/src/objects/Surface.svelte b/media/src/objects/Surface.svelte index f86c485f..abd3f928 100644 --- a/media/src/objects/Surface.svelte +++ b/media/src/objects/Surface.svelte @@ -68,6 +68,7 @@ selectObject, selectPoint, animate = () => {}, + playMode = 'loop', } = $props(); let rNum = 10; @@ -588,9 +589,36 @@ } }; + let modeSign = 1; + + function playModeCycle() { + if (playMode == 'once') { + playMode = 'loop'; + } else if (playMode == 'loop') { + playMode = 'bounce'; + } else { + playMode = 'once'; + } + } + const update = function (dt = 0) { - tau += dt / (t1 - t0); - if (tau > 1) tau %= 1; + tau += (modeSign * dt) / (t1 - t0); + + if (tau > 1) { + if (playMode == 'loop') { + tau %= 1; + } else if (playMode == 'once') { + tau = 1; + animation = false; + } else { + modeSign = -1; + tau = 2 - tau; + } + } + if (tau <= 0) { + modeSign = 1; + tau *= -1; + } if (isDynamic) evolveSurface(tVal); if (isRhoDynamic) { @@ -1062,6 +1090,8 @@ tau = 0; update(); }} + {playMode} + clicker={playModeCycle} /> {/if} diff --git a/media/src/objects/Vector.svelte b/media/src/objects/Vector.svelte index 675f451d..15787d87 100644 --- a/media/src/objects/Vector.svelte +++ b/media/src/objects/Vector.svelte @@ -59,6 +59,7 @@ render, onClose, gridStep, + playMode = 'loop', } = $props(); let minimize = $state(false); @@ -143,6 +144,16 @@ let isDynamic = $derived(dependsOn(params, 't')); let isDiscrete = $derived(dependsOn(params, 'n')); + function playModeCycle() { + if (playMode == 'once') { + playMode = 'loop'; + } else if (playMode == 'loop') { + playMode = 'bounce'; + } else { + playMode = 'once'; + } + } + $effect(updateVector); // recolor on demand @@ -250,13 +261,25 @@ return valuation; }; - const update = (dt = 0) => { - const { t0, t1 } = params; - const A = math.parse(t0).evaluate(); - const B = math.parse(t1).evaluate(); + let modeSign = 1; - tau += dt / (B - A); - if (tau > 1) tau %= 1; + const update = (dt = 0) => { + tau += (modeSign * dt) / (t1 - t0); + if (tau > 1) { + if (playMode == 'loop') { + tau %= 1; + } else if (playMode == 'once') { + tau = 1; + animation = false; + } else { + modeSign = -1; + tau = 2 - tau; + } + } + if (tau <= 0) { + modeSign = 1; + tau *= -1; + } updateVector(tVal); }; @@ -363,6 +386,8 @@ tau = 0; update(); }} + {playMode} + clicker={playModeCycle} /> {/if}